一、对变量延迟初始化
应用场景:如果一个类中,存在很多全局变量实例,我们不得不做许多的非空判断,即使我们非常确定他们不会为空。比如:
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编译器会自动检查该密封类有哪些子类,并强制要求你讲每一个子类所对应的的条件全部处理。
另外,密封类及其所有子类只能定义在同一文件的顶层位置,不能把嵌套在其他类中,这是被密封类底层的实现机制所限制。