Kotlin Null Safety (空值安全)
NullPointerException (NPE) 被稱為「十億美元的錯誤」,是 Java 程式最常崩潰的原因。
Kotlin 最強大的特性之一,就是將 空值 (Null) 納入型別系統中管理,在編譯時期就強制你處理 potential nulls。
Nullable vs Non-Nullable
在 Kotlin 中,預設變數 不能是 Null。
var a: String = "abc"
// a = null // 編譯錯誤!
如果你希望變數可以存 null,必須在型別後面加一個問號 ?:
var b: String? = "abc"
b = null // 合法
安全呼叫 (Safe Call ?.)
如果你想存取 b 的長度,直接寫 b.length 會報錯,因為編譯器知道 b 可能是 null。
你必須使用 ?.:
val l = b?.length
意思就是:「如果 b 不是 null,回傳長度;如果是 null,就回傳 null」。
(注意:此時 l 的型別會變成 Int?)
Elvis 運算子 (?:)
如果你不想要拿到 null,想要有個「預設值」怎麼辦?
這時就用 Elvis 運算子 ?: (長得像貓王 Elvis 的頭髮)。
val l = b?.length ?: -1
意思就是:「如果是 null,就給我 -1」。
雙驚嘆號 (!!)
有人稱之為 NPE 愛好者運算子。 它的作用是:「我發誓這變數絕對不是 null,如果是的話你就讓程式崩潰吧!」
val l = b!!.length
警告: 使用
!! 時請務必三思。它會繞過 Kotlin 的安全檢查,如果變數真的是 null,程式會直接拋出 NullPointerException。安全轉型 (as?)
嘗試轉型失敗時,不要噴 Exception,而是回傳 null。
val obj: Any = "Hello"
val num: Int? = obj as? Int // num 會是 null,不會崩潰
平台型別 (Platform Types)
這是 Kotlin 與 Java 互通時的一個特殊狀況。
當你呼叫 Java 程式碼時,如果 Java 程式碼沒有標註 @Nullable 或 @NotNull,Kotlin 分辨不出它到底是 String 還是 String?。
這時它的型別會顯示為 String! (驚嘆號)。
這代表:Kotlin 放棄檢查,風險自負。 你可以把它當作 String 也可以當作 String?,但如果它真的是 null 且你當作 String 用,就會在執行時噴 NPE。
// Java
public String getName() { return null; }
// Kotlin
val name = javaObj.name // 型別是 String!
println(name.length) // 編譯通過,但執行時崩潰!
7. 標準函式庫輔助
requireNotNull(x): 如果 x 是 null 拋出 IllegalArgumentException。checkNotNull(x): 如果 x 是 null 拋出 IllegalStateException。filterNotNull(): 過濾集合中的 null 元素。