一、對變量延遲初始化
應用場景:如果一個類中,存在很多全局變量實例,我們不得不做許多的非空判斷,即使我們非常確定他們不會爲空。比如:
class MainActivity : AppCompatActivity() {
private var recyclerAdapter: RecyclerAdapter? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
...
recyclerView.adapter = RecyclerAdapter(list)
...
}
override fun onClick(view:View?) {
...
recyclerAdapter?.notifyDataSetChanged()
...
}
}
使用lateinit關鍵字,他會告訴Kotlin編譯器,我會在晚些時候對這個變量進行初始化,這樣就不用在一開始的時候將它賦值爲null了:
class MainActivity : AppCompatActivity() {
private lateinit var recyclerAdapter: RecyclerAdapte
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
...
recyclerView.adapter = RecyclerAdapter(list)
...
}
override fun onClick(view:View?) {
...
recyclerAdapter.notifyDataSetChanged()
...
}
}
但是我們一定要注意,使用lateinit關鍵字一定要確保它在被調用前已經完成了和初始化工作,否則Kotlin無法保證程序的安全性。
另外,還可以通過代碼來判斷一個全局變量是否已經完成了初始化:
if(!::recyclerAdapter.isInitialized){
recyclerAdapter = RecyclerAdapter(list)
}
一、使用密封類優化代碼
看下面這段代碼:
interface Result
class Success(val msg: String) : Result
class Fail(val error: Error) : Result
fun getResult(result: Result) = when (result) {
is Success -> result.msg
is Fail -> result.error.message
else -> throw IllegalArgumentException()
}
我們使用when語句來判斷,每次都必需寫else,而且如果我們新增了一個繼承Result的類,但在getResult()方法中忘記添加相應的條件了,這時程序就會默認走else方法,導致崩潰。
密封類的關鍵字是 sealed class,用法非常簡單:
sealed class Result
class Success(val msg: String) : Result()
class Fail(val error: Error) : Result
可以看到,只是將interface關鍵在改成了sealed class.另外密封類是可繼承的類,所以在繼承它時要加上括號。
改成密封類之後,方法中的else條件就不需要了。
這是因爲當在when語句中傳入一個密封類變量作爲條件時,Kotlin編譯器會自動檢查該密封類有哪些子類,並強制要求你講每一個子類所對應的的條件全部處理。
另外,密封類及其所有子類只能定義在同一文件的頂層位置,不能把嵌套在其他類中,這是被密封類底層的實現機制所限制。