Kotlin之延遲初始化和密封類

1、延遲初始化

先看個(gè)實(shí)例看下延遲初始化的應(yīng)用場景:

private var messageAdapter: MessageListAdapter? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_message_list)
        message_list.layoutManager = LinearLayoutManager(this)
        initData()
        messageAdapter = MessageListAdapter(this, data)
        message_list.adapter = messageAdapter
        btn_add.setOnClickListener { 
            messageAdapter?.notifyDataSetChanged()
        }
    }

我們聲明了成員變量messageAdapter,它是在onCreate()中進(jìn)行初始化的,所以不得不先將成員變量messageAdapter初始化為null,同時(shí)它的類型聲明成MessageListAdapter?,這也就導(dǎo)致了每次調(diào)用messageAdapter都需要進(jìn)行判空處理。如果我們類中定義很多成員變量,那么所有的變量在使用前都是需要進(jìn)行判空處理的。解決辦法也很簡單:就是對成員變量進(jìn)行延遲初始化,這樣就不需要在一開始就初始化為null了。

private lateinit var messageAdapter: MessageListAdapter
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_message_list)
        message_list.layoutManager = LinearLayoutManager(this)
        initData()
        messageAdapter = MessageListAdapter(this, data)
        message_list.adapter = messageAdapter
        btn_add.setOnClickListener {
            messageAdapter.notifyDataSetChanged()
        Toast.makeText(this@MessageListActivity,"增加數(shù)據(jù)",Toast.LENGTH_SHORT).show()
        }
    }

this@MessageListActivity類似于Java中的MessageListActivity.this
可以看到我們在變量前加上了lateinit關(guān)鍵字,這樣就不用一開始初始化為null了,并且聲明類型為MessageListAdapter,由于這是不可空類型,那么我們在使用時(shí)就不需要進(jìn)行判空處理了。但是必須保證在任何地方調(diào)用時(shí),成員變量已經(jīng)初始化,否則會(huì)報(bào)UninitializedPropertyAccessException: lateinit property messageAdapter has not been initialized異常。
另外我們可以在初始化前進(jìn)行判斷,在未初始化時(shí)再進(jìn)行初始化,避免不必要的初始化。

 if (!::messageAdapter.isInitialized)
            messageAdapter = MessageListAdapter(this, data)

具體語法是::messageAdapter.isInitialized,這是固定寫法,用于判斷messageAdapter是否已經(jīng)初始化,如果沒有初始化則進(jìn)行初始化操作。

private lateinit var aa:Int
private lateinit var bb:Boolean

上面的聲明是會(huì)報(bào)錯(cuò)的

'lateinit' modifier is not allowed on properties of primitive types

注意:lateinit 不能修飾四類八種基礎(chǔ)類型int, double,boolean

2、使用密封類優(yōu)化代碼

先看下我們遇到的問題。

private fun getResultMsg(result: Result) = when (result) {
        is Success -> result.msg
        is Failure -> result.error.message
    }

上面代碼是編譯不通過的,必須增加else分支

private fun getResultMsg(result: Result) = when (result) {
        is Success -> result.msg
        is Failure -> result.error.message
        else ->"我是被逼的"
    }

但是實(shí)際上Result只可能是Success 或Failure,所以不可能走到else分支,但是我們又必須增加else分支為了滿足Kotlin的語法標(biāo)準(zhǔn)。另外如果我們新增了一個(gè)Unknow類實(shí)現(xiàn)了Result了,用于表示執(zhí)行未知的結(jié)果,但是忘記在getResultMsg中增加邏輯分支,會(huì)直接走到了else分支,這不是我們想要的結(jié)果,而且編譯器是不會(huì)提醒你。
下面我們就看下使用密封類如何解決上面的問題

//密封類的定義
sealed class Result

class Success(val msg: String) : Result()
class Failure(val error: Exception) : Result()
//調(diào)用
private fun getResultMsg(result: Result) = when (result) {
        is Success -> result.msg
        is Failure -> result.error.message
    }

密封類的定義也很簡單,使用sealed class來代替interface,這是已經(jīng)把Result定義成了密封類。
可以看到我們已經(jīng)不用增加無用的else分支了,這是為什么呢?
因?yàn)楫?dāng)在when語句中傳入一個(gè)密封類變量作為條件時(shí),Koltin編譯器會(huì)自動(dòng)檢查密封類有哪些子類,并強(qiáng)制要求每一個(gè)子類所對應(yīng)的條件全部處理。這樣就不會(huì)出現(xiàn)漏寫條件分支的情況了。
注意1:密封類及其子類只能定義在同一文件的頂層位置,不能嵌套在其他類中。
注意2:如果我們使用if來代替when進(jìn)行判斷,依然要增加else分支,密封類并不能解決問題。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容