Kotlin 为了尽可能地保证程序安全,规定变量不可变,变量不可为空。这种特性有时候会带来不便。
比如,如果类中存在很多的全局变量实例,为了保证它们能够满足 Kotlin 的空安全检查标准,就需要做很多的非空判断才行,即使我们能非常确定它们不会为空。
为了解决这个问题,Kotlin 中提供了两种延迟初始化的方式。
lateinit var
private lateinit var name:String
关键字 lateinit 作用是告诉编译器在编译期不要去检查变量是否为空,这样就不用一开始的时候就将它赋值为 null了。
需要注意的是,lateinit 只能修饰变量var,不能修饰常量val。而且只能用来修饰类属性,不能用来修饰局部变量,并且只能用来修饰对象,不能用来修饰基本类型(因为基本类型的属性在类加载后的准备阶段都会被初始化为默认值)。
当对一个全局变量使用了 lateinit 关键字时,请一定要确保它在被任何地方调用之前已经完成了初始化工作,否则 Kotlin 将无法保证程序的安全性。
另外还可以通过 isInitialized 检查是否初始化,具体代码如下:
private lateinit var name:String
fun test() {
if (!::name.isInitialized) {
name = "ok"
}
}
by lazy
by lazy 本身是一种属性委托。属性委托的关键字是 by。写法如下:
//用于属性延迟初始化
val name: Int by lazy { 1 }
//用于局部变量延迟初始化
public fun foo() {
val bar by lazy { "hello" }
println(bar)
}
注意:by lazy 只能修饰常量val,不能修饰变量var。和 lateinit 不同的是,by lazy可以修饰类属性,也可以修饰局部变量。另外要注意的是 by lazy 是在属性第一次使用时自动初始化,且只会加载一次。
lateinit var 和 by lazy 的区别
虽然两者都可以推迟属性初始化的时间,但是 lateinit var 只是让 Kotlin 编译期忽略了对属性没有初始化的检查,后续在哪里以及何时初始化还是需要开发者自己决定。
而 by lazy 真正做到了声明的同时也指定了延迟初始化时的行为,在属性被第一次被使用的时候进行初始化。