持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第7天,点击查看活动详情
在项目中我们或多或少地会对某个属性延迟初始化,一般情况下我们可以先定义变量,需要初始化的时候再赋值,或者使用lateinit
关键字,更多的时候我们可以使用by lazy
延迟初始化。
先定义后初始化
private var lazyValue: Int = 0
private fun test() {
lazyValue = 10
lazyValue.dec()
}
这种方式在在Java写法中使用的比较多
lateinit
lateinit var lazyValue:String
fun test() {
lazyValue = ""
}
只用lateinit关键字延迟初始化的时候不能对可空类型使用,不能对java中的基本数据类型使用,否则AS会抛出以下错误。
lateinit只能修饰变量var,而且它修饰的变量在使用之前必须初始化,否则会抛出下面的异常。
UninitializedPropertyAccessException: lateinit property lazyValue has not been initialized
by lazy
by lazy
是kotlin
中实现数据懒加载常用的一种方式,其中by
是kotlin
的关键字,用于实现委托,lazy
是一个方法。
val lazyValue by lazy {
"lazy"
}
println(lazyValue.length)
lazy()
方法源码如下
public actual fun <T> lazy(mode: LazyThreadSafetyMode, initializer: () -> T): Lazy<T> =
when (mode) {
LazyThreadSafetyMode.SYNCHRONIZED -> SynchronizedLazyImpl(initializer)
LazyThreadSafetyMode.PUBLICATION -> SafePublicationLazyImpl(initializer)
LazyThreadSafetyMode.NONE -> UnsafeLazyImpl(initializer)
}
其中mode
可以用来指定初始化该属性使用的线程安全模式,它有3中取值:
LazyThreadSafetyMode.SYNCHRONIZED
:单利模式,使用双重锁检查初始化属性,只会调用一次初始化的方法,是线程安全的。LazyThreadSafetyMode.PUBLICATION
:如果有多个线程同时调用,会多次调用初始化的方法,但是只有第一个返回的值才会作为委托属性的值。LazyThreadSafetyMode.NONE
:这种模式没有考虑多线程的情况,不应该在多线程的情况下使用。
在Android
中,我们一般使用的是by lazy {}
public actual fun <T> lazy(initializer: () -> T): Lazy<T> = SynchronizedLazyImpl(initializer)
这种情况属于LazyThreadSafetyMode.SYNCHRONIZED
,他会使用双重锁检查初始化属性,但是Android
中大部分都在UI线程属于线程安全的,如果仍然使用此模式,就会对性能有一定的影响,我们可以指定他的mode
为LazyThreadSafetyMode.NONE
,从而减少不必要的性能开销。
val lazyValue by lazy(LazyThreadSafetyMode.NONE) {
"lazy"
}