前言
空指針異常(NPE)是最為普遍與常見的異常舰攒,同時它也會引起諸如程序崩潰等非常嚴重的后果垂涯。為了避免出現(xiàn)NPE恼琼,常常需要開發(fā)者對變量進行判空處理炬太。特別是在Android中常常會使用‘鏈?zhǔn)健{(diào)用,但為了避免NPE隆敢,需要‘步步’判空,使得程序代碼啰嗦且難以維護崔慧。為解決此問題拂蝎,Kotlin提供了新的聲明,用于保證空安全惶室。
空安全
空安全簡單來說可在兩個階段進行:
- 聲明時保證空安全
- 使用時保證空安全
任何一個環(huán)節(jié)保證了空安全温自,則可避免空指針異常。
聲明時保證空安全
Java
在Java中并不支持在聲明變量時就保證空安全皇钞,即不支持在編譯時就判斷變量是否可能為空悼泌。Kotlin
Kotlin提供了新的方式,用于聲明變量是否可能為空夹界。聲明的語法為:
變量名:變量類型馆里?
添加?的變量類型表示其對象可能為空可柿。若不添加表示其對象不可能為空鸠踪,在編譯時就可以提前發(fā)現(xiàn)該問題。
var a: String = "abc"
a = null // 編譯錯誤
var b: String? = "abc"
b = null // ok
在這一例子中复斥,變量a沒有聲明為可空類型营密,若對其賦值為空,則會編譯報錯目锭。但對于變量b聲明為可空類型后评汰,可以令其為空纷捞。
使用時保證空安全
- Java
在java中無法再聲明時就保證空安全,為此要避免NPE被去,必須在使用變量時保證空安全主儡。最基本也是最常見的手段就是:
if (b != null){
//xxx
}
- Kotlin
在Kotlin中如果某個變量聲明為可空的類型,則在使用時也需要注意是否為空编振。Kotlin同樣支持像Java那樣顯式判空缀辩。同時也提供了安全調(diào)用符,即 踪央?.
val a = "Kotlin"
val b: String? = null
println(b?.length)
println(a?.length)
如果b不為空臀玄,就返回b.length,若b為空畅蹂,就返回null健无。該表達式的返回值類型為Int?
更為常見地,該調(diào)用符也可以支持’鏈?zhǔn)健{(diào)用:
bob?.department?.head?.name
若其中任何一個環(huán)節(jié)為空液斜,則返回空累贤。
安全調(diào)用也可以出現(xiàn)在賦值的左側(cè)。這樣少漆,如果調(diào)用鏈中的任何一個接收者為空都會跳過賦值臼膏,而右側(cè)的表達式根本不會求值:
person?.department?.head = managersPool.getManager()
空處理
- Java
當(dāng)我們有一個可空的引用 b 時,我們可以說“如果 b 非空示损,我使用它渗磅;否則使用某個非空的值 x”:
if (b != null){
return b.length;
} else {
return -1;
}
- Kotlin
要實現(xiàn)在變量為空時的處理,Kotlin不僅支持像Java那樣的顯式賦值检访,還擁有更為簡單的操作符始鱼,即Elvis 操作符 ?:
val l = b?.length ?: -1
如果 ?: 左側(cè)表達式非空,elvis 操作符就返回其左側(cè)表達式脆贵,否則返回右側(cè)表達式医清。 請注意,當(dāng)且僅當(dāng)左側(cè)為空時卖氨,才會對右側(cè)表達式求值会烙。
額外操作符
- Kotlin
在Kotlin中還支持一些Java不支持的新的操作符,如!!操作符双泪。
val l = b!!.length
如果該調(diào)用不為空持搜,則返回預(yù)期值,若為空焙矛,則拋出空指針異常葫盼。
安全類型轉(zhuǎn)換:如果對象不是目標(biāo)類型,那么常規(guī)類型轉(zhuǎn)換可能會導(dǎo)致 ClassCastException村斟。 另一個選擇是使用安全的類型轉(zhuǎn)換贫导,如果嘗試轉(zhuǎn)換不成功則返回 null:
val aInt: Int? = a as? Int