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 元素。