Kotlin lateinit vs by lazy

Kotlin lateinit和by lazy的区别

一、简要说明

Koltin中属性在声明的同时也要求要被初始化,否则会报错。

但是有些应用场景,不想在声明的时候就初始化,那么可以使用lateinit.
延时初始化属性就是不必在类实例化时初始化它,可以根据需要在程序运行期初始化,而没有lateinit声明的非可空类型属性必须在类实例化时初始化。

其实就是让编译期在检查时不要因为属性变量未被初始化而报错。

PS:

  • 延时初始化属性要求:
  • 不能是可空类型;
  • 只能使用为var声明;
  • lateinit关键字应该放在var之前。

二、实际使用对比

简单的代码示例对比:

未使用lateinit情况

1
2
3
4
5
class Employee {
var name: String = ""
var id: Int = 0
var department =Department()
}

1
2
3
4
class Department {
var id: Int = 0
var name:String ="default"
}

1
2
3
4
5
//在调用时,Debug可以看出区别
fun test(){
val emp = Employee()
print(emp.department)
}

调试结果:
without

使用lateinit

1
2
3
4
5
class Employee {
var name: String = ""
var id: Int = 0
lateinit var department : Department
}

1
2
3
class Department {
var id: Int = 0
var name:String ="default"

1
2
3
4
5
fun test(){
val emp = Employee()
emp.department = Department()//在需要的时候进行初始化
print(emp.department)
}

调用结果:
withlateinit

三、对比

by lazy,Kotlin中提供一种委托属性,使用by关键字声明。

  1. 惰性加载属性和延迟初始化属性类似,只有第一次访问该属性时才进行初始化

  2. 不同的是惰性加载属性使用lazy函数声明委托属性,而延迟初始化属性lateinit关键字修饰属性。

  3. 惰性加载属性必须是val的,而延迟初始化属性必须是var的。

  4. lazy 应用于单例模式的时候(if-null-then-init-else-return),而且当且仅当变量被第一次调用的时候,委托方法才会执行。

四、区别?怎么用?

  1. 如果是值可修改的变量(即在之后的使用中可能被重新赋值),使用lateInit模式

  2. 如果变量的初始化取决于外部对象(例如需要一些外部变量参与初始化),使用lateInit模式。这种情况下,lazy模式也可行但并不直接适用。

  3. 如果变量仅仅初始化一次并且全局共享,且更多的是内部使用(依赖于类内部的变量),请使用lazy模式。从实现的角度来看,lateinit模式仍然可用,但lazy模式更有利于封装你的初始化代码。
    综上所述,不考虑对变量值是否可变的控制,lateinit模式是lazy模式的超集,你可以在任何使用lazy模式的地方用lateinit模式替代,反之则不然。但在可能的情况下,请尽量使用lazy模式,因为lateinit模式在函数中暴露了太多的逻辑代码,使得代码更加混乱,相比而言,lazy模式更好地封装了细节,且更安全。

总结而言,对于变量的初始化,优先选择lazy模式,其次再考虑late模式……实在不行,选择最原始的方法手动实现。

Neil Liu wechat
个人微信,欢迎交流
让我感受下知识的力量~