Kotlin淺析延遲初始化與密封類的實(shí)現(xiàn)方法
一、lateinit延遲初始化關(guān)鍵字
Kotlin中很多語(yǔ)法特性,如變量不可變,變量不可為空,等等 這些特性都是為了盡可能地保證程序安全而設(shè)計(jì)的,比如你的類中存在很多全局變量實(shí)例,為了保證它們的能夠滿足Kotlin的空指針檢查語(yǔ)句標(biāo)準(zhǔn),你不得不做非空判斷保護(hù),即使你非常確定它們不會(huì)為空。
下面距離看一下 :
class MainActivity : AppCompatActivity() { private var s: String? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) s = "test" Log.d("TAG", "onCreate: ${s!!.length}") } }
我們將s 設(shè)置為了全局變量 , 但是它的賦值工作在onCreate()方法進(jìn)行的,因此不得不將s賦值為null。
雖然你確定在打印前已經(jīng)將s賦值成功,但是打印s的長(zhǎng)度仍然要進(jìn)行判空處理才行,否則編譯不通過(guò)。
當(dāng)你的代碼中越來(lái)越多的全局變量實(shí)例時(shí),這個(gè)問(wèn)題就會(huì)變得越來(lái)越明顯,到時(shí)候可能必須寫大量額外判空處理的代碼,卻只是為了滿足Kotlin的編譯要求。
幸運(yùn)的是,這個(gè)問(wèn)題有解決辦法的且非常之簡(jiǎn)單,就是對(duì)全局變量進(jìn)行延遲初始化。
初始化使用的關(guān)鍵字 lateinit ,它可以高速編譯器,我會(huì)在晚些時(shí)候?qū)@個(gè)變量進(jìn)行初始化,這樣就不用一開(kāi)始就賦值為null了。
class MainActivity : AppCompatActivity() { private lateinit var s: String override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) s = "test" Log.d("TAG", "onCreate: ${s.length}") } }
可以看到,加上了lateinit關(guān)鍵字 ,這樣一開(kāi)始就不用賦值為null了,打印長(zhǎng)度的時(shí)候也不用進(jìn)行判空處理了,當(dāng)然使用lateinit關(guān)鍵字 也不是沒(méi)有風(fēng)險(xiǎn),如果沒(méi)有進(jìn)行賦值,那么程序一定會(huì)崩潰,并拋出異常。
另外,我們可以通過(guò)代碼來(lái)判斷全局變量是否已完成了初始化工作,這樣某些時(shí)候可以有效避免重復(fù)對(duì)某一個(gè)變量進(jìn)行初始化操作。
class MainActivity : AppCompatActivity() { private lateinit var s: String override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) if (!::s.isInitialized) { s = "test" } Log.d("TAG", "onCreate: ${s.length}") } }
二、使用密封類優(yōu)化代碼
新建一個(gè)Kotlin文件,代碼如下 :
interface Result class Success(val msg: String) : Result class Failure(val error: Exception) : Result
這里定義了一個(gè)Result接口,用于表示某個(gè)操作的執(zhí)行結(jié)果,接口中沒(méi)有編寫任何內(nèi)容。然后定義了兩個(gè)類去實(shí)現(xiàn)Result接口:一個(gè)Success類用于表示成功時(shí)結(jié)果,一個(gè)Failure類用于表示失敗時(shí)結(jié)果。
接下來(lái)再定義一個(gè)getResultMsg()方法 ,用于獲取最后執(zhí)行結(jié)果的信息,代碼如下:
fun getResultMsg(result: Result) = when (result) { is Success -> result.msg is Failure -> result.error.message else -> throw IllegalArgumentException() }
getResultMsg()方法中接受一個(gè)Result參數(shù),我們通過(guò)when語(yǔ)句來(lái)判斷,如果Result屬于Success就返回成功的消息,如果Result是Failure就返回錯(cuò)誤的信息,到目前為止代碼是沒(méi)什么問(wèn)題的,煩人的是不得不寫一個(gè)else條件語(yǔ)句,否則Kotlin編譯不通過(guò),其實(shí)代碼永遠(yuǎn)也走不到else里 因?yàn)橹挥袃煞N類型的存在,只是為了滿足Kotlin的語(yǔ)法而已。
另外,編寫else條件還有一個(gè)潛在的風(fēng)險(xiǎn),如果我們新增一個(gè)Unknown類并實(shí)現(xiàn)了Result接口,用于表示未知的執(zhí)行結(jié)果,但是忘記了在getResultMsg()方法中添加相應(yīng)的條件,編譯器不會(huì)提醒我們的,而是直接進(jìn)入else條件里面去,從里面拋出異常并導(dǎo)致程序崩潰。
Kotlin的密封類很好的解決了此問(wèn)題,密封類的關(guān)鍵字是sealed class ,它的用法同樣很簡(jiǎn)單,我們可以輕松的將Result接口改造成密封類寫法:
sealed class Result class Success(val msg: String) : Result() class Failure(val error: Exception) : Result() fun getResultMsg(result: Result) = when (result) { is Success -> result.msg is Failure -> result.error.message }
代碼沒(méi)什么變化,只是將interface改成了 sealed class。密封類是一個(gè)可繼承的類,因此在繼承它的時(shí)候還需要加上一對(duì)括號(hào)。
密封類的優(yōu)點(diǎn)是,可以再getResultMsg() 方法中取消else條件語(yǔ)句。
為什么取消掉else條件語(yǔ)句還能編譯通過(guò)呢,Kotlin編譯器會(huì)自動(dòng)檢查該密封類有哪些子類,并強(qiáng)制要求將每一個(gè)子類所對(duì)應(yīng)的條件全部處理。這樣就可以保證,即使沒(méi)有else條件,也不可能出現(xiàn)漏寫的情況,如果現(xiàn)在新增一個(gè)Unknown類,并也讓它繼承自Result,此時(shí)getResultMsg()方法就一定會(huì)報(bào)錯(cuò),必須添加Unknown語(yǔ)句條件才能編譯通過(guò)。
注意:密封類及其所有子類只能定義同一個(gè)文件的頂層位置,不能嵌套在其他類中,這也是被密封類底層實(shí)現(xiàn)機(jī)制所限制的。
到此這篇關(guān)于Kotlin淺析延遲初始化與密封類的實(shí)現(xiàn)方法的文章就介紹到這了,更多相關(guān)Kotlin延遲初始化內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android Studio連接MySql實(shí)現(xiàn)登錄注冊(cè)(附源代碼)
登錄注冊(cè)是常用的一個(gè)功能,正好今天用android studio 做一個(gè)類似于這樣的登錄軟件,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05Android百度地圖定位后獲取周邊位置的實(shí)現(xiàn)代碼
這篇文章主要為大家詳細(xì)介紹了Android百度地圖定位后獲取周邊位置的實(shí)現(xiàn)代碼,準(zhǔn)確獲取周邊地理位置,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-01-01Android右滑返回上一個(gè)界面的實(shí)現(xiàn)方法
這篇文章主要介紹了Android右滑返回上一個(gè)界面的實(shí)現(xiàn)方法的相關(guān)資料,希望通過(guò)本文能幫助到大家,讓大家實(shí)現(xiàn)這樣的功能,需要的朋友可以參考下2017-10-10基于Flutter實(shí)現(xiàn)圖片選擇和圖片上傳
Flutter?的圖片選擇插件很多,包括了官方的?image_picker,multi_image_picker(基于2.0出了?multi_image_picker2)等等。本文將利用這些插件實(shí)現(xiàn)圖片選擇和圖片上傳,需要的可以參考一下2022-03-03Android上實(shí)現(xiàn)easyconfig(airkiss)方法
本篇文章主要給大家講解了在Android系統(tǒng)上實(shí)現(xiàn)easyconfig(airkiss)的方法,有這方面需要的朋友參考學(xué)習(xí)下吧。2018-01-01android ListView結(jié)合x(chóng)utils3仿微信實(shí)現(xiàn)下拉加載更多
本篇文章主要介紹了android ListView結(jié)合x(chóng)utils3仿微信實(shí)現(xiàn)下拉加載更多,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-11-11