很多同學剛上手使用Kotlin知道它有針對Java NullPointerException的管理,而在Kotlin中?和!!均是和NullPointerException有關系,可他們的區別到底是什么呢?為什么別人開發的項目中出現了好多"?",而我讀起來卻滿臉問號。

不懂就問百度呀,確實有人解釋它們的區別,比如:

這是輸入 "kotlin ?和!!"搜索到的百度第一條答案,確實這位說的沒錯。不過我覺得對於一個剛接觸KT(Kotlin)的新手來說,他恐怕需要有漢語八級才能透徹理解這兩句話的意思。
先闡述兩個概念:
"?"加在變量名后,系統在任何情況不會報它的空指針異常。
"!!"加在變量名后,如果對象為null,那么系統一定會報異常!
先拿Java代碼舉個例子
ArrayList<String> myList = null; // 創建一個null的隊列 Log.d("TAG", "-->> List Size = " + myList.size());
這個例子中,執行到Log打印隊列長度時,大家都知道系統一定會報NullPointerException。然而如果在KT中,在調用myList的時候在它后面加上一個問號myList?.size()
,當myList為null的時候直接會打印List Size = null
並不會有null異常出現。
當使用Android Studio把上面那段Java自動轉換成KT代碼寫法后:
val myList : ArrayList<String>? = null Log.d("TAG", "-->> List Size = ${myList!!.size}")
編譯器為什么自動把myList.size()
變成了myList!!.size
呢,為什么加上的是感嘆號不是問號。
這是因為編譯器在轉化時為了保證代碼轉化前后的一致性所造成的。換句話說,在Java上出異常的,轉化到KT上,編譯器任然會讓他保持拋出異常,NullPointerException也是如此。
所以結合上下文可以看得出,!!加上去后好像並沒有和之前Java代碼有什么區別嘛,該null的地方任然會拋出異常。所以大多數情況下都會使用?來檢測null,輪不到!!出場。!!只會在你需要對某對象進行非空判斷,並且需要拋出異常時才會使用到。
那我們接下來着重講解一下?到底怎么用。
在聲明對象時,把它跟在類名后面,表示這個類允許為null;
在調用對象時,把它跟在對象后面,表示如果為null程序就會視而不見。
如下列代碼:
// 這是聲明一個變量,問號跟在類名后面 var room: Room? = Room() private fun checkRoom() { // 因為加上了問號,所以可以任意的把room變成空 room = null // 因為在調用時加上了問號,所以程序不會拋出異常 Log.d("TAG", "-->> room name = ${room?.roomName}") }
再舉個不用?的例子:
// 這樣程序就默認的給room加上了!!,從此以后room不允許為null var room: Room = Room() private fun checkRoom() { // 當把null賦給room時,從編譯的時候就已經不通過 room = null // 並且編譯器建議把對象后面的問號刪除,因為這個對象永遠不為空 Log.d("TAG", "-->> room name = ${room.roomName}") }
所以加上?是一種安全的寫法,它體現了Kotlin null safety的特性。
KT的語法很靈動,定義參數還可以寫成
val room: Room? = Room() // 先實例化一個room,並且room可以為空 val room: Room? = null // 不實例化了,開始room就是空的 val room: Room = Room() // 實例化一個room,並且room永遠不能為空 val room = Room() // 和上一行代碼一樣,是KT最常用的簡寫語法
然而加上問號以后程序就萬事大吉永遠擺脫了NullPointerException的煩惱?我們再看下一段代碼:
val roomList: ArrayList<Room>? = null if (roomList?.size > 0) { Log.d("TAG", "-->> 房間數不是0") }
當我們判斷list.size的時候,編譯器會告訴我們"Operator call corresponds to a dot-qualified call 'roomList?.size.compareTo(0)' which is not allowed on a nullable receiver 'roomList?.size'."。大概意思是,當roomList為null的時,它的size返回就是"null",但是"null"不可以和int值比大小,所以編譯器建議我們寫成roomList?.size!! > 0
。
沒錯,經過編譯器的建議加上了!!,我們程序運行到這行代碼,roomList為null時它一定會報異常。所以是不是必須得在外面套一層if(roomList != null)
這種Java常見語句才能避免異常嗎?
當然Kotlin不會讓程序出現這種啰嗦的代碼,所以里面提供了對象A ?: 對象B
表達式,並且取消了Java中的條件表達式 ? 表達式1 : 表達式2
這個三元表達式。
?:表示的意思是,當對象A值為null的時候,那么它就會返回后面的對象B。
val roomList: ArrayList<Room>? = null val mySize= roomList?.size ?: 0
此時mySize的值就為0,因為roomList?.size為空。
所以我們可以把上面的代碼改成這樣:
val roomList: ArrayList<Room>? = null if (roomList?.size ?: 0 > 0) { // 這一行添加了?: Log.d("TAG", "-->> 房間數不是0") }
就目前為止使,用上面的?和?:基本上能避免程序中出現的所有NullPointerException。
作者:Jason_Samuel
鏈接:https://www.jianshu.com/p/51b2e5aa3dd8
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯系作者獲得授權並注明出處。