疯狂kotlin讲义连载之Kotlin的基础类型--null安全
null安全可以說是Kotlin語言對Java的重大改進之一,這樣可以避免Java編程時令人恐懼的“NullPointerException”(簡稱:NPE)。但話說回來,null安全不過是各種現代語言玩剩下的東西。
1 非空類型和可空類型
下面先看一個簡單的例子。
程序清單:codes\02\2.8\NullableTest.kt
var str = "fkit"
// 由于str轉換為Int有可能失敗,故num有可能沒有值
// 因此不能使用Int來聲明num的類型
var num: Int = str.toIntOrNull()
var num: Int? = str.toIntOrNull()
println(num)
}
對比上面兩行粗體字代碼:第一行代碼聲明num的類型為Int,第二行代碼聲明num的類型為Int?。程序中第一行粗體字代碼無法通過編譯,第二行粗體字代碼能通過編譯。其中Int?就是可空類型,這種類型的變量可接受Int值和null兩種情況;而Int類型的變量則只接受Int值,不能接受null的情況。由于str是一個String變量,當程序試圖把String變量轉換為Int值時,有可能轉換成功(如果變量值是形如"123"的字符串),也有可能轉換失敗(本程序就轉換失敗了)。轉換失敗時,就無法成功返回Int值,此時將會返回null,因此必須使用Int?類型的變量來存儲轉換結果。
對于可能發生“值缺失”的情況,編譯器會自動推斷該變量的類型為可空類型。例如如下代碼:
var n = str.toIntOrNull()
需要指出的是,只有可空類型的變量或常量才能接受null,非空類型的變量和常量不能接受null。
Kotlin對可空類型進行了限制:如果不加任何處理,可空類型不允許直接調用方法、訪問屬性。因此,通過可空類型與非空類型的區分,Kotlin即可在程序中避免空指針異常。例如如下程序(程序清單同上):
var bStr: String? = "fkit"
aStr = null // 錯誤,aStr不接受null值
bStr = null // 正確
// 編譯通過,aStr不可能為null,運行時不可能導致NPE
println(aStr.length)
// 編譯不能通過,不可能導致NPE
println(bStr.length)
上面代碼中定義了aStr和bStr兩個變量,其中aStr是非空String類型,因此aStr變量不允許賦值為null;而bStr是可空的String類型,bStr變量允許被賦值為null;程序可以直接調用aStr的方法和屬性,但aStr變量的值不可能為nul的,因此可以避免NPE;Kotlin對可空類型進行了限制,可空類型不允許直接調用方法和屬性,因此程序不能直接調用bStr的方法或屬性,這樣也可避免NPE。
2 先判斷后使用
可空類型的變量不允許直接調用方法或屬性,但可以先判斷該變量不為null,然后再去調用該變量的屬性和方法。例如如下代碼。
程序清單:codes\02\2.8\CheckNull.kt
f
var b: String? = "fkit"
// 先判斷b不為null,然后訪問b的length屬性
var len = if (b != null) b.length else -1
println("b的長度:${len}")
b = null
// 先判斷b不為null,然后調用b的length屬性
if (b != null && b.length > 0) {
// 訪問b的length屬性
println(b.length)
}
else {
println("空字符串")
}
}
上面程序定義了String?(可空類型)的變量b,這樣程序不能直接調用變量b的方法和屬性,Kotlin要求程序先判斷b不為null,接下來程序即可在該條件下調用b的方法或屬性。
對于非空Boolean類型而言,它可以接受3個值,true、false或null,因此對Boolean?類型變量進行判斷時,需要使用Boolean?變量顯式與true、false值進行比較。例如如下代碼。
f
var b: Boolean? = null
if( b == true ){
println("為真")
}
}
如果將if分支改為如下形式:
if( b ){
println("為真")
}
編譯器會報錯:type mismatch: inferred type is Boolean? but Boolean was expected,這是因為Kotlin的if條件必須是Boolean類型,而Boolean?與Boolean本質上是兩個不同類型,因此編譯器會報錯。
3 安全調用
安全調用則在Java中已出現很多年了,只不過沒有出現在Java官方語法中——如果讀者熟悉Spring EL,一定見過如下用法。
user?.dog?.name
上面表達式語言表示如果user不為null,則返回user的dog屬性;如果dog屬性值不為null,則繼續獲取dog屬性值的name屬性值。反過來,如果user為null,或user.dog為null,上面表達式語言都不會導致NPE,而是整個表達式返回null——這就是Spring EL的安全調用。
Kotlin的安全調用也完全與此類似,例如如下代碼。
程序清單:codes\02\2.8\SafeCall.kt
var b: String? = "fkit"
println(b?.length) // 輸出4
b = null
println(b?.length) // 輸出null
}
上面程序中變量b的類型是String?,因此程序使用了?.安全調用來訪問b的length屬性,當b為null時,程序也不會引發NPE,而是返回null。
與Spring EL類似的是,Kotlin的安全調用完全也支持鏈式調用,就像Spring EL的用法一樣:
user?.dog?.name
上面代碼表示安全獲取user的dog的name屬性值,如果user或user.dog為null,整個表達式將會返回null。
此外,安全調用還可與let全局函數結合使用,例如如下代碼(程序清單同上)。
val myArr: Array<String?> = arrayOf("fkit", "fkjava", null, "crazyit")
for (item in myArr) {
// 當item不為null時才調用let函數
item?.let { println(it) }
}
上面粗體字代碼使用安全調用來調用let函數,這樣只有當item元素不為null才會執行let函數。上面程序調用let函數時傳入一個Lambda表達式作為函數參數。
4 Elvis運算
Elvis運算也是一種早就滿大街的小技巧了,其實就是if else的簡化寫法。對比如下代碼。
程序清單:codes\02\2.8\Elvis.kt
var b: String? = "fkit"
// 先判斷b不為null,然后訪問b的length屬性
var len1 = if (b != null) b.length else -1
println(len1);
b = null
// 使用Elvis運算符
var len2 = b?.length ?: -1
println(len2);
}
上面第一行粗體字代碼使用傳統if分支進行判斷,當b不為null時返回b.length,否則返回-1;第二行粗體字代碼則使用?:運算符,該運算符就是Elvis——它的含義是:如果?:左邊的表達式不為null時,則返回左邊表達式的值,否則返回?:右邊表達式的值。
由此可見?:其實就是if分支的簡化寫法。
此外,由于Kotlin的return、throw都屬于表達式,因此它們也都可以用在?:運算符的右邊。例如如下代碼片段:
val data = ……
val email = data["email"] ?: throw IllegalArgumentException("沒有指定Email信息!")
5 強制調用
強制調用時為NPE愛好者準備的——如果讀者依然喜歡Java那種簡單、粗暴的方式:不管變量是否為null,程序都直接調用該變量的方法或屬性,Kotlin也為這種用法提供了支持,用!!.即可強制調用可空變量的方法或屬性,這樣強制調用可能引發NPE。例如如下代碼。
程序清單:codes\02\2.8\ForceCall.kt
var b: String? = "fkit"
println(b!!.length) // 輸出4
b = null
println(b!!.length) // 刪除null
// 定義一個元素可空的數組
val myArr: Array<String?> = arrayOf("fkit", "fkjava", null, "crazyit")
for (item in myArr) {
// 當item不為null時才調用let函數
item!!.let { println(it) }
}
}
上面程序就是將前面的安全調用程序中?.安全調用該為!!.強制調用,當可空變量b為null時,b!!.length將會引發NPE;與前面安全調用類似的是,強制調用也可作用于let()函數,此時不管item元素是否為null,程序都會對該元素調用let()函數,因此也可能導致NPE。
第二期:juejin.im/post/59c1d6…
第三期:juejin.im/post/59e407…
第四期:juejin.im/post/59ed77…
第五期:juejin.im/post/59eec3…
第六期:juejin.im/post/59effb…
第七期:juejin.im/post/59f153…
第八期:juejin.im/post/59f283…
第九期:juejin.im/post/59f686…
第十期:juejin.im/post/59f7ea…
第十一期:juejin.im/post/59f953…
相關書籍《瘋狂Android講義》https://item.jd.com/11689014.html總結
以上是生活随笔為你收集整理的疯狂kotlin讲义连载之Kotlin的基础类型--null安全的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: crypto-js RC4和hash_h
- 下一篇: 多种方式读取文件内容