Kotlin Tutorial(9)物件與null by Michael | CodeData
top

Kotlin Tutorial(9)物件與null

分享:
tags: null kotlin

Kotlin Tutorial(8)字串 << 前情

在許多資訊技術都可以看到「null」,例如資料庫與Java。在設計應用程式的時候,程式設計師通常也會把null加入設計的邏輯,例如使用null值表示沒有符合查詢條件的資料。不過null卻很容易造成應用程式發生錯誤,以Java程式設計語言來說,就是發生NullPointerException後讓應用程式中斷與結束。

null

null值在資訊技術通常表示一個「沒有任何資料的值」:

  • 一個可以指定給物件變數的值,表示這個物件變數沒有任何對應的資料。對Java程式設計語言來說,null值表示沒有參考值(reference)對應到一個實體(instance)。
  • 在Java程式設計語言,除了基本資料型態(primitive)以外,物件變數都可以指定null值,稱為null reference。
  • 一個指定為null值的物件變數,在使用它的時候(例如呼叫函式),會發生執行時期例外,如果沒有執行額外的控制,就會導致程式中斷並結束。

例如下面的Java程式片段:

String name = "Simon";
System.out.println(name.toUpperCase());
// 顯示:SIMON
// ...
name = null;
System.out.println(name.toUpperCase());
// 發生例外:
// Exception in thread "main" java.lang.NullPointerException

為了預防錯誤的發生,必須在程式碼執行必要的判斷,例如下面的Java程式片段:

String name = "Simon";
// ...
name = null;

// 判斷變數不是null值後,再執行後續的工作    
if (name != null) {
    System.out.println(name.toUpperCase());
}

Sir Charles Antony Richard Hoare,通常被稱為Tony Hoare或C. A. R. Hoare,是英國的計算機科學家。在2009年的一次會議,他為發明null reference而道歉。下面是原文翻譯後的內容:

我稱之為十億美元的錯誤。我在1965年發明null reference。當時,我正在設計第一個物件導向程式設計語言(ALGOL W)的綜合型態系統。 我的目標是確保所有物件的使用都應該是絕對安全的,並且由編譯器自動執行檢查。但是,我無法抗拒使用null reference的誘惑,因為它很容易實現。這導致了無數的錯誤,漏洞和系統崩潰,這可能在過去四十年中造成了十億美元的痛苦和破壞。

原文請參考:Tony Hoare #Apologies and retractions

不允許指定null值的變數

Kotlin為了預防null造成的問題,而且簡化應用程式的設計,在宣告物件變數的時候,預設的作法是不允許指定null值給物件變數:

// 使用一般的語法宣告字串物件變數
var name: String = "Simon"

// 編譯錯誤,不可以指定null值
//name = null

// 不可以指定null值的變數,可以直接呼叫函式
// 也不會因為null值發生例外
println(name.toUpperCase())

不允許指定null值的字串變數,可以直接呼叫各種功能的函式:

var name3: String = "Simon"

// 判斷變數是否為空白
println("name3 isBlank: ${name3.isBlank()}")
// 判斷變數是否沒有字元
println("name3 isEmpty: ${name3.isEmpty()}")

可以指定null值的變數

如果因為特殊的需求,或是為了跟Java應用程式的相容性,你也可在宣告物變數的時候,讓它可以指定null值。不過為了預防因為null造成的例外,Kotlin針對允許null值的變數設計了一些作法:

// 宣告可以指定null值的變數
var name2: String? = "Mary"

// 可以指定null值
name2 = null

// 編譯錯誤,因為可以指定null值的變數
// 不允許直接呼叫函式
// println(name2.length)

// 如果先經過null值的判斷...
if (name2 != null) {
    // 就可以直接使用
    println(name2.length)
}    

為了預防null造成的問題,還有簡化應用程式的設計,Kotlin為呼叫函式加入了特別的作法:

// 宣告可以指定null值的變數
var name2: String? = "Mary"

// 必須在變數名稱後面多一個問號
// 變數是null值的時候,不會發生例外,不過會傳回null
println(name2?.length)

name2 = "Sam"
// 變數不是null值的時候,顯示呼叫函式執行後的結果3
println(name2?.length)

name2 = null
// 在變數名稱後面加入兩個驚嘆號(!!)
//println(name2!!.length)
// 發生例外
// Exception in thread "main" kotlin.KotlinNullPointerException

呼叫函式的時候,在變數名稱後面加入兩個驚嘆號(!!),這樣的作法在變數是null值的時候,會造成應用程式因為例外而中斷。在一般的情況下,都不應該使用這樣的作法。

允許指定null值的字串變數,在呼叫各種功能函式的時候,就會有一些限制:

var name: String? = null

// 判斷變數是否為null或空白
println("name.isNullOrBlank(): ${name.isNullOrBlank()}")
// 判斷變數是否為null或沒有字元
println("name.isNullOrEmpty(): ${name.isNullOrEmpty()}")

// 編譯錯誤,不可以直接呼叫
//println("name.isBlank(): ${name.isBlank()}")
//println("name.isEmpty(): ${name.isEmpty()}")

println("name.isBlank(): ${name?.isBlank()}")
println("name.isEmpty(): ${name?.isEmpty()}")

如果應用程式需要判斷變數是否為null值,根據判斷結果執行不同的工作,例如下面的程式片段:

val length: Int

if (name2 != null)
    length = name2.length
else
    length = 0

println("length: $length")

上面的應用可以使用Kotlin提供的「?:」運算式:

// 如果name2是null值,就使用「?:」後面的值
println( name2?.length ?: 0 )

陣列與元素

物件儲存在陣列的時候,除了變數本身外,元素也有null值的問題。你可以根據應用程式的需求,使用下面程式片段的作法宣告陣列:

// 變數與元素都不可以指定null值
var names3: Array<String> = arrayOf("One", "Two", "Three")
// 變數不可以指定null值,但是元素可以
var names4: Array<String?> = arrayOf("One", "Two", "Three")
// 變數與元素都可以指定null值
var names5: Array<String?>? = arrayOf("One", "Two", "Three")

一個變數與元素都不可以指定null值的陣列,在使用的時候,都可以直接呼叫函式執行需要的工作:

// 變數與元素都不可以指定null值
var names = arrayOf("Simon", "Mary", "Sam")

// 編譯錯誤,變數不可以指定null值
// names = null

// 編譯錯誤,元素不可以指定null值
// names[0] = null

for (element in names) {
    print("${element.length}\t")
}

如果陣列變數不可以指定null值,但是因為應用程式的需求,讓元素可以指定null值,使用陣列元素的時候,就必須遵守相關的規則:

// 變數不可以指定null值,但是元素可以
val names2 = arrayOf<String?>("Simon", "Mary", "Sam")
// 元素可以指定null值
names2[0] = null

for (element in names2) {
    // 編譯錯誤,因為元素可以指定null值
    // print("${element.length}\t")
    print("${element?.length}\t")
}

下一步

完成Kotlin程式設計語言的基礎,還有認識基本的物件與null值以後,接下來準備開始認識物件導向程式設計,為應用程式設計需要的類別。

相關的檔案都可以在GitHub瀏覽與下載。

https://github.com/macdidi5/Kotlin-Tutorial

分享:
按讚!加入 CodeData Facebook 粉絲群

相關文章

留言

留言請先。還沒帳號註冊也可以使用FacebookGoogle+登錄留言

關於作者

張益裕。目前的工作是講師與作者,專長是教育訓練課程規劃、教材編製與課程推廣,技術書籍與專欄寫作。涵蓋的領域有OOAD、Java程式設計、JavaFX、Java Embedded、Android與SQL。已出版電子書Google Play圖書Pubu

熱門論壇文章

熱門技術文章