Kotlin中空判斷處理操作實(shí)例
Kotlin中的一個(gè)偉大創(chuàng)前舉就是空指針的處理,在代碼的編譯階段就能檢測(cè)可能出現(xiàn)的空指針問(wèn)題,示例代碼如下:
data class Person(var name: String? = null) fun sayHello(name: String) { println("Hello $name") } fun main() { val person = Person("Even") if (person.name != null) { sayHello(person.name) } }
在IntelliJ中,如上代碼會(huì)報(bào)錯(cuò),如下:
提示的錯(cuò)誤信息翻譯為:智能強(qiáng)制轉(zhuǎn)換為’String’是不可能的,因?yàn)?rsquo;person.name’是一個(gè)可變屬性,此時(shí)可能已經(jīng)被更改了。
要想編譯通過(guò),需要這樣做:
sayHello(person.name!!)
哎?我記得學(xué)Kotlin的時(shí)候有解釋說(shuō)如果已經(jīng)判斷了不是空了的話,就不需要添加 !! 符號(hào)的,為什么這里不添加的話會(huì)報(bào)錯(cuò)呢?其實(shí)原因就是報(bào)錯(cuò)信息上提示的,因?yàn)閚ame是用var修飾的,而且這是一個(gè)成員變量,雖然你做了非空的判斷,但是判斷之后,這個(gè)成員屬性有可能在其它線程被修改了,比如在其他線程設(shè)置為null了,所以,這樣的話就會(huì)出現(xiàn)空指針異常了,所以添加 !! 符號(hào)來(lái)解決報(bào)錯(cuò)不是最佳實(shí)踐,在我這個(gè)示例中,我們知道沒(méi)有開(kāi)多線程去修改person的name屬性,所以可以加 !! 來(lái)解決,但是最好不要這樣做,如果我們知道name屬性不會(huì)被修改,則可以使用val修飾,如下:
可以看到,此時(shí)不需要添加 !! 也不報(bào)錯(cuò)了,因?yàn)镮DE知道name是一個(gè)不可變屬性,判斷了不是空之后,就永遠(yuǎn)不可能是空了。
有時(shí)候,name屬性就需要發(fā)生變化,就必須聲明為var,此時(shí)怎么解決呢?,可以通過(guò)添加局部變量解決,如下:
如上代碼,IDE沒(méi)有報(bào)錯(cuò)。我們通過(guò)添加一個(gè)val類型的name局部變量來(lái)保存person.name的值,這樣的話,判斷了name為不為空之后,即使person.name在子線程被設(shè)置為空了,但是局部變量name不會(huì)受到影響。我們?cè)陂喿x一些系統(tǒng)源碼的時(shí)候,不論是Java源碼或是Kotlin的源碼,經(jīng)常發(fā)現(xiàn)別人在判斷一個(gè)對(duì)象的屬性的可空性的時(shí)候,都是先聲明一個(gè)局部變量保存該對(duì)象屬性再來(lái)判斷,不懂事的時(shí)候就會(huì)奇怪別人為什么要多此一舉,現(xiàn)在明白了,別人是為了預(yù)防直接判斷對(duì)象屬性出現(xiàn)的多線程修改帶來(lái)的問(wèn)題。
添加局部變量的話,即使是var類型的局部變量IDE也能判斷是否為空,示例如下:
如上代碼,可以看到,局部變量name是可變類型的,但是也不需要添加 !! 符號(hào),因?yàn)関ar類型的局部變量不會(huì)被子線程修改,所以判斷了不為空之后就不會(huì)為空。最后賦值了”Lily“,然后傳給sayHello(name),這里并沒(méi)有做非空判斷啊,sayHello接受的是不可空的String,但是name是一個(gè)可空String啊,道理也很簡(jiǎn)單,因?yàn)檫@是局部變量,沒(méi)有子線程的干擾,IDE能檢測(cè)到name在傳給sayHello之前是賦值了”Lily"的,之后沒(méi)有再賦值為null也是能檢測(cè)出來(lái)的,所以這里不需要做可空判斷也能編譯通過(guò)。如果沒(méi)有賦值“Lily",則IDE就不知道name是否為空了,就會(huì)報(bào)錯(cuò),如下:
或者,如果我們使用的是一個(gè)成員變量,即使前一句代碼賦值了下一句就用也是會(huì)報(bào)錯(cuò)的,原因就是它有可能在子線程被設(shè)置為null了,如下:
所以,Kotlin是真的很強(qiáng),如果你在使用一個(gè)變量,只要IDE沒(méi)報(bào)錯(cuò),你就可以放心的使用,不需要做空判斷,你可以放心,運(yùn)行時(shí)不會(huì)有空指針問(wèn)題的。如果IDE報(bào)錯(cuò)了,就是有可能發(fā)生空指針的,此時(shí)你就不要強(qiáng)制添加 !! 來(lái)逃避問(wèn)題了,一定要做合理的空指針判斷處理。如果你使用Java的話,要不要做空指針處理IDE是沒(méi)有提示的,你只能自己用腦子去想要不要做空指針判斷處理,事實(shí)往往是我們根本就不去想要不要做處理,或者即使思考過(guò)了,也會(huì)有思考出錯(cuò)的時(shí)候,比如可能出現(xiàn)空指針的地方,但是你寫代碼時(shí)你認(rèn)為不會(huì)出現(xiàn)空指針,所以你沒(méi)做非空判斷處理,則運(yùn)行時(shí)就有可能出現(xiàn)空指針異常了。而Kotlin就會(huì)有提示,只要IDE沒(méi)報(bào)錯(cuò)就不用做空指針處理,只要IDE報(bào)錯(cuò)了就要做空指針處理,這真是爽歪歪啊,你不需要去思考什么時(shí)候應(yīng)該添加空指針判斷處理了!
注:這個(gè)可空判斷也適用于類型智能轉(zhuǎn)換,這個(gè)知識(shí)點(diǎn)在官網(wǎng)教程上也找到了答案:https://kotlinlang.org/docs/typecasts.html#unsafe-cast-operator,相關(guān)內(nèi)容如下:
Note that smart casts work only when the compiler can guarantee that the variable won’t change between the check and the usage. More specifically, smart casts can be used under the following conditions:
val local variables - always, with the exception of local delegated properties.
val properties - if the property is private or internal or if the check is performed in the same module where the property is declared. Smart casts cannot be used on open properties or properties that have custom getters.
var local variables - if the variable is not modified between the check and the usage, is not captured in a lambda that modifies it, and is not a local delegated property.
var properties - never, because the variable can be modified at any time by other code.
附:?.和!!.
其實(shí)kotlin是非常人性話的,你定義了一個(gè)可為空的變量但是你依然可以去操作的。我們修改一下上面的寫法:
val a:String = "我加小明" val b:String ?= null val c:String? = "我加小明" ? println(a.length) ? println(b?.length) ? ?println(c!!.length)
這樣編譯就通過(guò)。
這里的**?.**就是相當(dāng)于Java的如果為空就返回null 而kotlin強(qiáng)制讓我們?nèi)ヌ幚?,這樣就避免了很多空指針異常
if(b==null) return null;
當(dāng)然如果你不想直接為null,你說(shuō)當(dāng)為空時(shí)我想自己去處理,kotlin還有語(yǔ)法**?:**
val b:String ?= null println(b?.length?:"我錯(cuò)了")
!!. 表示我任性,告訴編譯器不要去做非空檢查,為空就拋異常
總結(jié)
到此這篇關(guān)于Kotlin中空判斷處理操作的文章就介紹到這了,更多相關(guān)Kotlin空判斷處理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決ViewPager和SlidingPaneLayout的滑動(dòng)事件沖突問(wèn)題
下面小編就為大家分享一篇解決ViewPager和SlidingPaneLayout的滑動(dòng)事件沖突問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-01-01Android?PowerManagerService?打開(kāi)省電模式
這篇文章主要介紹了Android?PowerManagerService打開(kāi)省電模式,文章通告省電模式的打開(kāi)過(guò)程、什么是?battery?saver?sticky?模式兩部分展開(kāi)詳情,感興趣的朋友可以參考一下2022-08-08Android實(shí)現(xiàn)底部滾輪式選擇彈跳框
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)底部滾輪式選擇彈跳框,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08Android Flutter基于WebSocket實(shí)現(xiàn)即時(shí)通訊功能
WebSocket是一種在單個(gè)TCP連接上進(jìn)行全雙工通信的協(xié)議。本文將利用Flutter WebSocket實(shí)現(xiàn)即時(shí)通訊功能,文中示例代碼講解詳細(xì),感興趣的可以了解一下2022-03-03Android6.0 storage目錄sd卡存儲(chǔ)的路徑創(chuàng)建詳解
這篇文章主要介紹了Android6.0 storage目錄sd卡存儲(chǔ)的路徑創(chuàng)建的相關(guān)資料,需要的朋友可以參考下2017-01-01Android與iOS包體優(yōu)化及一鍵自動(dòng)打包腳本
這篇文章主要為大家介紹了安卓與iOS包體優(yōu)化及一鍵自動(dòng)打包腳本詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09android使用SharedPreferences進(jìn)行數(shù)據(jù)存儲(chǔ)
Android平臺(tái)給我們提供了一個(gè)SharedPreferences類,它是一個(gè)輕量級(jí)的存儲(chǔ)類,特別適合用于保存軟件配置參數(shù)。有興趣的可以了解一下。2017-02-02Android 6.0以上權(quán)限拒絕打開(kāi)權(quán)限設(shè)置界面的解決方法
今天小編就為大家分享一篇Android 6.0以上權(quán)限拒絕打開(kāi)權(quán)限設(shè)置界面的解決方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-07-07