Kotlin語言基礎(chǔ)筆記
Kotlin流程控制語句筆記
Kotlin操作符重載與中綴表示法筆記
Kotlin擴(kuò)展函數(shù)和擴(kuò)展屬性筆記
Kotlin空指針安全(null-safety)筆記
Kotlin類型系統(tǒng)筆記
Kotlin面向?qū)ο缶幊坦P記
Kotlin委托(Delegation)筆記
Kotlin泛型型筆記
Kotlin函數(shù)式編程筆記
Kotlin與Java互操作筆記
Kotlin協(xié)程筆記
多年的java開發(fā)經(jīng)驗(yàn)總結(jié)得出,至少50%以上的線上bug都是NPE(NullPointException)引起的。在java代碼中充斥著大量的非空判斷,如果是有多層的對(duì)象,比如person.getAddress().getCity(),你需要判斷person非空,然后判斷address非空,只有兩個(gè)都非空時(shí),才能安全的獲取到city。這樣的代碼非常冗余和惡心。
現(xiàn)在我們來看看Kotlin做了那些事情讓我們來避免NPE錯(cuò)誤。
1. 可為null類型
在Kotlin中通常我們直接定義的類型是不可為null的,如下:
data class Person(val name:String)
fun main(args: Array<String>) {
var s = "abc"
s = null //編譯錯(cuò)誤:null can not be a value of a non-null type String
var i = 1
i = null //編譯錯(cuò)誤:null can not be a value of a non-null type Int
var p = Person("Denny")
p = null //編譯錯(cuò)誤:null can not be a value of a non-null type Person
}
如果要允許為null,我們需要在變量的類型后面加個(gè)?號(hào)。如下:
data class Person(val name:String)
fun main(args: Array<String>) {
var s: String? = "abc"
s = null
var i:Int? = 1
i = null
var p:Person? = Person("Denny")
p = null
var list:MutableList<Int>? = mutableListOf(1, 2, 3)
list = null
}
2. 安全調(diào)用
上面的例子中,如果調(diào)用s.length的話,這將是不安全的,編譯器直接報(bào)錯(cuò)。

npe
編譯器已經(jīng)告訴你了要使用安全調(diào)用(
?.)或者非空斷言調(diào)用(!!.)才被允許在String?類型上。
fun main(args: Array<String>) {
var s: String? = "abc"
s = null
println(s?.length) //打印null
println(s!!.length) //拋出Exception in thread "main" kotlin.KotlinNullPointerException異常
}
另外我們?cè)倏纯聪旅孢@段有趣的代碼:
fun main(args: Array<String>) {
var s: String? = "abc"
println(s is Any) //打印true
println(s is Any?) //打印true
s = null
println(s is Any) //打印false
println(s is Any?) //打印true
}
安全調(diào)用在鏈?zhǔn)秸{(diào)用上非常有用,比如上面java代碼person.getAddress().getCity(),在Kotlin中使用安全調(diào)用的話就是person?.getAddress()?.getCity()。只要person或者address有一個(gè)為null的話,整個(gè)表達(dá)式就返回null。比java中用2個(gè)if來判斷非空好多了。
如果對(duì)某個(gè)非空值執(zhí)行某個(gè)操作,安全調(diào)用操作符可以和let一起使用。比如:
fun main(args: Array<String>) {
val list = listOf("a", "b", null)
println(list)
list.forEach { it?.let { println(it) } }
}
輸出
[a, b, null]
a
b
最后你還可以使用Elvis錯(cuò)作符,之前的文章有說過。
fun main(args: Array<String>) {
var name:String? = null
name = name?:"Unknown"
println(name) //打印Unknown
}