Kotlin中?和!!的區別


很多同學剛上手使用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
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯系作者獲得授權並注明出處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM