1. 事前準備
在本程式碼實驗室中,您將瞭解「是否可為空值」相關的知識以及 null 安全的重要性。「是否可為空值」是許多程式設計語言中常見的概念,代表您可以不對變數設定任何值。在 Kotlin 中,我們特別設計了對「是否可為空值」的處理機制來確保 null 安全。
必要條件
- 具備 Kotlin 程式設計的基本知識,包括變數、如何存取變數中的方法和屬性,以及
println()和main()函式 - 熟悉 Kotlin 條件式,包含
if/else陳述式和布林運算式
課程內容
- 什麼是
null? - 可為空值和不可為空值類型之間的差異。
- 什麼是
null安全、其重要性,以及 Kotlin 如何確保null安全。 - 如何使用
?.安全呼叫運算子和!!非空值斷言運算子,來存取可為空值變數的方法和屬性。 - 如何使用
if/else條件式執行null檢查。 - 如何使用
if/else運算式將可為空值變數轉換成不可為空值類型。 - 如何使用
if/else運算式或?:Elvis 運算子,在可為空值變數為null時提供預設值。
軟硬體需求
- 可使用 Kotlin Playground 的網路瀏覽器。
2. 使用可為空值變數
什麼是 null?
在單元 1 中,我們已經瞭解到在宣告變數時,必須立即為其指派一個值。舉例來說,當宣告 favoriteActor 變數時,可以立即為其指派 "Sandra Oh" 字串值。
val favoriteActor = "Sandra Oh"

不過,沒有喜愛的演員時該怎麼辦?您可能想為變數指派 "Nobody" 或 "None" 值,但這並不是好方法,因為程式會將 favoriteActor 變數解讀為含有 "Nobody" 或 "None" 值,而不是完全沒有值。在 Kotlin 中,可以使用 null 表明變數沒有任何相關聯的值。

如要在程式碼中使用 null,請按照下列步驟操作:
- 在 Kotlin Playground 中,將
main()函式主體中的內容替換成設為null的favoriteActor變數:
fun main() {
val favoriteActor = null
}
- 使用
println()函式輸出favoriteActor變數的值,然後執行以下程式:
fun main() {
val favoriteActor = null
println(favoriteActor)
}
輸出結果如以下程式碼片段所示:
null
為變數重新指派 null
在前面的課程中,您已瞭解可以為使用 var 關鍵字定義的變數重新指派相同類型的不同值。舉例來說,您可以為已使用某個名稱宣告的 name 變數重新指派另一個名稱,只要新名稱為 String 類型即可。
var favoriteActor: String = "Sandra Oh"
favoriteActor = "Meryl Streep"
有時候,您在宣告變數後可能會想為該變數指派 null。舉例來說,在宣告喜愛的演員後,您發現自己根本不想公開自己喜愛的演員。在這種情況下,為 favoriteActor 變數指派 null 會很有用。
瞭解不可為空值和可為空值的變數
如要為 favoriteActor 變數重新指派 null,請按照下列步驟操作:
- 將
val關鍵字變更為var關鍵字,然後將favoriteActor變數指定為String類型,並為其指派自己喜愛演員的名字:
fun main() {
var favoriteActor: String = "Sandra Oh"
println(favoriteActor)
}
- 移除
println()函式:
fun main() {
var favoriteActor: String = "Sandra Oh"
}
- 為
favoriteActor變數重新指派null,然後執行以下程式:
fun main() {
var favoriteActor: String = "Sandra Oh"
favoriteActor = null
}
系統會顯示下列錯誤訊息:

在 Kotlin 中,變數有可為空值和不可為空值類型之分:
- 可為空值類型是「可以」儲存
null值的變數。 - 不可為空值類型是「無法」儲存
null值的變數。
只有當您明確允許某個變數儲存 null 值時,該變數才屬於可為空值類型。如錯誤訊息所示,String 資料類型屬於不可為空值類型,因此您無法為該變數重新指派 null。

如要在 Kotlin 中宣告可為空值變數,您需要在類型結尾加上 ? 運算子。舉例來說,String? 類型可儲存字串或 null 值,而 String 類型只能儲存字串。如要宣告可為空值變數,您必須明確新增可為空值類型。如果沒有可為空值類型,Kotlin 編譯器會推論該變數屬於不可為空值類型。
- 將
favoriteActor變數類型從String資料類型變更為String?資料類型:
fun main() {
var favoriteActor: String? = "Sandra Oh"
favoriteActor = null
}
- 在重新指派
null前後輸出favoriteActor變數,然後執行以下程式:
fun main() {
var favoriteActor: String? = "Sandra Oh"
println(favoriteActor)
favoriteActor = null
println(favoriteActor)
}
輸出結果如以下程式碼片段所示:
Sandra Oh null
favoriteActor 變數原本儲存的是字串,接著重新指派了 null。
試試看
現在,您已瞭解如何使用可為空值的 String? 類型,那麼現在可以透過 Int 值將變數初始化,並為其重新指派 null 嗎?
寫入可為空值的 Int 值
- 移除
main()函式中的所有程式碼:
fun main() {
}
- 建立一個
number變數,其中含有可為空值的Int類型,然後為該變數指派10值:
fun main() {
var number: Int? = 10
}
- 輸出
number變數,然後執行以下程式:
fun main() {
var number: Int? = 10
println(number)
}
輸出內容與預期結果相符,如下所示:
10
- 為
number變數重新指派null,以確認變數可為空值:
fun main() {
var number: Int? = 10
println(number)
number = null
}
- 在程式的最後一行新增其他
println(number)陳述式,然後執行此程式:
fun main() {
var number: Int? = 10
println(number)
number = null
println(number)
}
輸出內容與預期結果相符,如下所示:
10 null
3. 處理可為空值變數
在前面的課程中,您已學習如何使用 . 運算子存取不可為空值變數的方法和屬性。本節將說明如何使用這個運算子存取可為空值變數的方法和屬性。
如要存取不可為空值的 favoriteActor 變數的屬性,請按照下列步驟操作:
- 移除
main()函式中的所有程式碼,然後宣告String類型的favoriteActor變數,並為其指派喜愛演員的名字:
fun main() {
var favoriteActor: String = "Sandra Oh"
}
- 使用
length屬性輸出favoriteActor變數值中的字元數,然後執行以下程式:
fun main() {
var favoriteActor: String = "Sandra Oh"
println(favoriteActor.length)
}
輸出內容與預期結果相符,如下所示:
9
favoriteActor 變數的值中有「9」個字元 (包括空格)。您喜愛的演員名字中的字元數可能有所不同。
存取可為空值變數的屬性
假設您要讓 favoriteActor 變數設為可為空值,以便讓沒有喜愛演員的使用者能為變數指派 null。
如要存取可為空值的 favoriteActor 變數的屬性,請按照下列步驟操作:
- 將
favoriteActor變數類型變更為可為空值類型,然後執行以下程式:
fun main() {
var favoriteActor: String? = "Sandra Oh"
println(favoriteActor.length)
}
系統會顯示下列錯誤訊息:

這類錯誤屬於「編譯錯誤」。如先前的程式碼實驗室所述,當程式碼中有語法錯誤,導致 Kotlin 無法編譯程式碼時,就會發生編譯錯誤。
Kotlin 會刻意套用語法規則,以確保 null「安全」,即保證「不會意外呼叫 null 變數」。然而,這並不表示變數不能為 null,而是表示當您存取變數成員時,該變數不能為 null。
這點非常重要,因為如果在應用程式執行期間嘗試存取 null 變數成員 (稱為「null 參照」),應用程式會因 null 變數不含任何屬性或方法而停止運作。這類停止運作的狀況稱為「執行階段錯誤」,即在程式碼完成編譯及執行後發生的錯誤。
由於 Kotlin 具有確保 null 安全的特性,因此 Kotlin 編譯器會對可為空值類型強制執行「null 檢查」,以免發生這類執行階段錯誤。「Null 檢查」是指在存取變數並將其視為不可為空值類型之前,先檢查變數是否可為 null 的程序。如果您要將可為空值的值當做不可為空值類型使用,就必須明確執行 null 檢查。如要瞭解相關資訊,請參閱本程式碼實驗室後續的「使用 if/else 條件式」一節。
在本範例中,系統不允許直接參照 favoriteActor 變數的 length 屬性 (因為該變數有可能是 null),這會導致程式碼在編譯時間執行失敗。
接下來,您將瞭解用來處理可為空值類型的各種技巧和運算子。
使用 ?. 安全呼叫運算子
您可以使用 ?. 安全呼叫運算子,以存取可為空值變數的方法或屬性。
如要使用 ?. 安全呼叫運算子存取方法或屬性,請在變數名稱後方加上 ? 符號,並使用 . 標記存取方法或屬性。
?. 安全呼叫運算子可讓您安全存取可為空值變數,因為 Kotlin 編譯器會阻止變數成員存取 null 參照,並對存取的成員回傳 null。
如要安全存取可為空值的 favoriteActor 變數屬性,請按照下列步驟操作:
- 在
println()陳述式中,將.運算子替換成?.安全呼叫運算子:
fun main() {
var favoriteActor: String? = "Sandra Oh"
println(favoriteActor?.length)
}
- 執行以下程式,並確認輸出內容是否符合預期:
9
您喜愛的演員名字中的字元數可能有所不同。
- 為
favoriteActor變數重新指派null,然後執行以下程式:
fun main() {
var favoriteActor: String? = null
println(favoriteActor?.length)
}
輸出內容如下:
null
請注意,即使嘗試存取 null 變數的 length 屬性,該程式仍不會停止運作。安全呼叫運算式只會回傳 null。
使用 !! 非空值斷言運算子
您也可以使用 !! 非空值斷言運算子,來存取可為空值變數的方法或屬性。

您需要在可為空值變數之後加上 !! 非空值斷言運算子,之後跟著 . 運算子,最後是方法或屬性 (不含任何空格)。
顧名思義,如果您使用 !! 非空值斷言運算子,即表示您聲明變數的值並非 null,無論變數是否為該值都是如此。
與 ?. 安全呼叫運算子不同,如果可為空值變數確實是 null,使用 !! 非空值斷言運算子可能會導致系統擲回 NullPointerException 錯誤。因此,只有在變數始終為不可為空值,或已設定適當的例外狀況處理方式時,才應使用該斷言運算子。如果例外狀況未得到妥善處理,會造成執行階段錯誤。本課程的後續單元將說明例外狀況處理方式。
如要使用 !! 非空值斷言運算子存取 favoriteActor 變數的屬性,請按照下列步驟操作:
- 為
favoriteActor變數重新指派您喜愛的演員名字,然後在println()陳述式中將?.安全呼叫運算子替換成!!非空值斷言運算子:
fun main() {
var favoriteActor: String? = "Sandra Oh"
println(favoriteActor!!.length)
}
- 執行以下程式,並確認輸出內容是否符合預期:
9
您喜愛的演員名字中的字元數可能有所不同。
- 為
favoriteActor變數重新指派null,然後執行以下程式:
fun main() {
var favoriteActor: String? = null
println(favoriteActor!!.length)
}
系統會顯示 NullPointerException 錯誤,內容如下:

這個 Kotlin 錯誤顯示,您的程式在執行期間停止運作。因此,除非您確定變數不是 null,否則不建議使用 !! 非空值斷言運算子。
使用 if/else 條件式
您可以在 if/else 條件式中使用 if 分支版本來執行「null 檢查」。

如要執行 null 檢查,可以使用 != 比較運算子檢查可為空值變數是否不等於 null。
if/else 陳述式
if/else 陳述式可與 null 檢查搭配使用,如下所示:

空值檢查與 if/else 陳述式搭配使用時有以下優點:
nullableVariable != null運算式的null檢查會用作if條件式。if分支版本內的主體 1 會假設變數不可為null。因此,在這個主體中,您可以自由存取變數的方法或屬性,就好像該變數是不可為空值變數一般,而無需使用?.安全呼叫運算子或!!非空值斷言運算子。else分支版本內的主體 2 會假設變數為null。因此,在這個主體中,您可以新增在變數為null時執行的陳述式。else分支版本為選用項目。當null檢查失敗時,您只能使用if條件式來執行null檢查,且不執行預設動作。
如果有多行程式碼使用可為空值變數,那麼將 null 檢查與 if 條件式搭配使用較為簡便。相比之下,?. 安全呼叫運算子則適合用於可為空值變數的單一參照。
如要編寫為 if/else 陳述式來對 favoriteActor 變數執行 null 檢查,請按照下列步驟操作:
- 再次為
favoriteActor變數指派您喜愛的演員名字,然後移除println()陳述式:
fun main() {
var favoriteActor: String? = "Sandra Oh"
}
- 新增包含
favoriteActor != null條件式的if分支版本:
fun main() {
var favoriteActor: String? = "Sandra Oh"
if (favoriteActor != null) {
}
}
- 在
if分支版本的主體中,新增可接受"The number of characters in your favorite actor's name is ${favoriteActor.length}."字串的println陳述式,然後執行以下程式:
fun main() {
var favoriteActor: String? = "Sandra Oh"
if (favoriteActor != null) {
println("The number of characters in your favorite actor's name is ${favoriteActor.length}.")
}
}
輸出內容與預期結果相符。
The number of characters in your favorite actor's name is 9.
您喜愛的演員名字中的字元數可能有所不同。
請注意,由於您會在 null 檢查後存取 if 分支版本內的 length 方法,因此可直接使用 . 運算子存取名字長度方法。同時,Kotlin 編譯器知道 favoriteActor 變數絕不會是 null,所以允許直接存取屬性。
- 選用:新增
else分支版本,以處理演員名字為null的情形:
fun main() {
var favoriteActor: String? = "Sandra Oh"
if (favoriteActor != null) {
println("The number of characters in your favorite actor's name is ${favoriteActor.length}.")
} else {
}
}
- 在
else分支版本的主體中,新增可接受"You didn't input a name."字串的println陳述式:
fun main() {
var favoriteActor: String? = "Sandra Oh"
if (favoriteActor != null) {
println("The number of characters in your favorite actor's name is ${favoriteActor.length}.")
} else {
println("You didn't input a name.")
}
}
- 為
favoriteActor變數指派null,然後執行以下程式:
fun main() {
var favoriteActor: String? = null
if(favoriteActor != null) {
println("The number of characters in your favorite actor's name is ${favoriteActor.length}.")
} else {
println("You didn't input a name.")
}
}
輸出內容與預期結果相符,如下所示:
You didn't input a name.
if/else 運算式
您還可以將 null 檢查與 if/else 運算式結合,藉此將可為空值變數轉換成不可為空值變數。

如要為 if/else 運算式指派不可為空值類型,請按照下列步驟操作:
- 將
nullableVariable != nullnull檢查用作if條件式。 if分支版本內的主體 1 會假設變數不可為null。因此,在這個主體中,您可以存取變數的方法或屬性,就好像該變數是不可為空值變數一般,而無需使用?.安全呼叫運算子或!!非空值斷言運算子。else分支版本內的主體 2 會假設變數為null。因此,在這個主體中,您可以新增在變數為null時執行的陳述式。- 在主體 1 和主體 2 的最後一行中,您必須使用會產生不可為空值類型的運算式或值,這樣一來,就能在
null檢查通過或失敗時指派給不可為空值變數。
如要使用 if/else 運算式重新編寫程式,讓程式只使用一個 println 陳述式,請按照下列步驟操作:
- 為
favoriteActor變數指派您喜愛的演員名字:
fun main() {
var favoriteActor: String? = "Sandra Oh"
if (favoriteActor != null) {
println("The number of characters in your favorite actor's name is ${favoriteActor.length}.")
} else {
println("You didn't input a name.")
}
}
- 建立
lengthOfName變數,然後為其指派if/else運算式:
fun main() {
var favoriteActor: String? = "Sandra Oh"
val lengthOfName = if (favoriteActor != null) {
println("The number of characters in your favorite actor's name is ${favoriteActor.length}.")
} else {
println("You didn't input a name.")
}
}
- 從
if和else這兩個分支版本中移除println()陳述式:
fun main() {
var favoriteActor: String? = "Sandra Oh"
val lengthOfName = if (favoriteActor != null) {
} else {
}
}
- 在
if分支版本的主體中新增favoriteActor.length運算式:
fun main() {
var favoriteActor: String? = "Sandra Oh"
val lengthOfName = if (favoriteActor != null) {
favoriteActor.length
} else {
}
}
favoriteActor 變數的 length 屬性可直接使用 . 運算子存取。
- 在
else分支版本的主體中新增0值:
fun main() {
var favoriteActor: String? = "Sandra Oh"
val lengthOfName = if (favoriteActor != null) {
favoriteActor.length
} else {
0
}
}
當名字為 null 時,0 值會成為預設值。
- 在
main()函式的結尾加上可接受"The number of characters in your favorite actor's name is $lengthOfName."字串的println陳述式,然後執行以下程式:
fun main() {
var favoriteActor: String? = "Sandra Oh"
val lengthOfName = if (favoriteActor != null) {
favoriteActor.length
} else {
0
}
println("The number of characters in your favorite actor's name is $lengthOfName.")
}
輸出內容與預期結果相符,如下所示:
The number of characters in your favorite actor's name is 9.
您使用的名稱字元數可能有所不同。
使用 ?: Elvis 運算子
?: Elvis 運算子是可與 ?. 安全呼叫運算子搭配使用的運算子。使用 ?: Elvis 運算子時,您可以在 ?. 安全呼叫運算子回傳 null 時加上預設值。這個做法與 if/else 運算式類似,但更為常用。
如果變數「不是」null,系統會執行 ?: Elvis 運算子之前的運算式。如果變數「是」null,系統會執行 ?: Elvis 運算子之後的運算式。

如要修改先前的程式以使用 ?: Elvis 運算子,請按照下列步驟操作:
- 移除
if/else條件式,然後將lengthOfName變數設為可為空值的favoriteActor變數,並使用?.安全呼叫運算子呼叫其length屬性:
fun main() {
var favoriteActor: String? = "Sandra Oh"
val lengthOfName = favoriteActor?.length
println("The number of characters in your favorite actor's name is $lengthOfName.")
}
- 在
length屬性之後加上?:Elvis 運算子以及0值,然後執行以下程式:
fun main() {
var favoriteActor: String? = "Sandra Oh"
val lengthOfName = favoriteActor?.length ?: 0
println("The number of characters in your favorite actor's name is $lengthOfName.")
}
輸出內容會與先前的輸出內容相同:
The number of characters in your favorite actor's name is 9.
4. 結語
恭喜!您已學會是否可為空值的相關知識,以及如何運用各種運算子進行管理。
摘要
- 可將變數設為
null,代表該變數不儲存任何值。 - 不可將
null指派給不可為空值變數。 - 可將
null指派給可為空值變數。 - 如要存取可為空值變數的方法或屬性,需要使用
?.安全呼叫運算子或!!非空值斷言運算子。 - 可以將
if/else陳述式與null檢查搭配使用,以在不可為空值的結構定義中存取可為空值變數。 - 可使用
if/else運算式將可為空值變數轉換成不可為空值類型。 - 可以使用
if/else運算式或?:Elvis 運算子,在可為空值變數為null時,提供預設值。
