Kotlin是一种现代化的编程语言,提供了许多有用的功能来简化开发过程。其中,”lateinit”和”lazy”是两个常用的关键字,用于在需要时延迟初始化变量。Kotlin中lateinit和lazy的区别是:1、lateinit和lazy的适用场景;2、lateinit和lazy的初始化时机。”lateinit”适用于在构造函数之后才能初始化的非空变量,而”lazy”适用于在名列前茅次访问变量时进行初始化,并希望后续访问直接使用已初始化的值的情况。
一、lateinit(延迟初始化)
- “lateinit”是Kotlin中用于延迟初始化非空变量的关键字。
- 通过使用”lateinit”关键字,我们可以在声明变量时不需要立即初始化它,而是在后续的代码中进行初始化。这对于某些情况下,变量的初始化必须在构造函数之后进行的场景非常有用。
- 使用”lateinit”关键字时,必须满足以下条件:
- 变量类型必须为非空类型(即不能是可空类型)。
- 变量不能有自定义的getter或setter。
- 变量不能是原生类型(如Int、Long等)。
示例:
lateinit var name: String
// 在后续代码中进行初始化
name = "John Doe"
注意:如果在使用”lateinit”关键字声明的变量在使用前没有进行初始化,会抛出”lateinit property has not been initialized”异常。
二、lazy(惰性初始化)
- “lazy”是Kotlin标准库中的函数,用于实现惰性初始化。
- 通过”lazy”函数,我们可以在名列前茅次访问变量时进行初始化,之后的访问会直接使用初始化后的值,避免重复初始化的开销。
- “lazy”函数接受一个lambda表达式作为参数,在名列前茅次访问变量时,该lambda表达式会被调用,并返回初始化后的值。
- 使用”lazy”关键字时,可以保证变量的初始化是线程安全的。
示例:
val value: String by lazy {
println("Initializing...")
"Hello"
}
// 名列前茅次访问value,会输出"Initializing..."
println(value)
// 第二次访问value,直接使用已初始化的值,不会再输出"Initializing..."
println(value)
输出:
Initializing...
Hello
Hello
三、区别与用途
- lateinit和lazy的适用场景: “lateinit”适用于在构造函数之后才能初始化的非空变量,而”lazy”适用于在名列前茅次访问变量时进行初始化,并希望后续访问直接使用已初始化的值的情况。
- lateinit和lazy的初始化时机: “lateinit”在后续代码中进行初始化,需要手动处理可能的未初始化异常。而”lazy”在名列前茅次访问时进行初始化,并保证线程安全。
延伸阅读
Kotlin中的by lazy委托属性
线程安全: “by lazy”委托属性的初始化是线程安全的,保证了多线程环境下的正确性。这得益于其内部使用的是线程安全的双重检查锁定(double-checked locking)。
自定义初始化: 除了前面提到的lambda表达式初始化方式,我们还可以使用自定义的初始化方法来实现”by lazy”委托属性。只需实现Lazy接口的getValue方法即可。示例:
val name: String by lazy {
// 自定义初始化方法
initName()
}
private fun initName(): String {
println("Initializing...")
return "John Doe"
}
非常量委托属性: “by lazy”通常用于常量属性,即只能进行一次初始化。但实际上,它也可以用于非常量属性,只要在之后的访问中不再需要重新初始化。
示例:
var count: Int by lazy {
// 可变属性,非常量
0
}
fun increment() {
count++
}
“by lazy”委托属性是Kotlin中非常有用的特性之一,它使得我们能够在需要时延迟初始化变量,并且保证了初始化的线程安全性。无论是常量属性还是非常量属性,”by lazy”都能为我们带来便利。在实际开发中,合理使用”by lazy”委托属性可以提高代码的性能和可维护性。