Kotlin使用by lazy延迟初始化

545 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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会抛出以下错误。

微信截图_20220531230952.png

lateinit只能修饰变量var,而且它修饰的变量在使用之前必须初始化,否则会抛出下面的异常。

UninitializedPropertyAccessException: lateinit property lazyValue has not been initialized

by lazy

by lazykotlin中实现数据懒加载常用的一种方式,其中bykotlin的关键字,用于实现委托,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中取值:

  1. LazyThreadSafetyMode.SYNCHRONIZED:单利模式,使用双重锁检查初始化属性,只会调用一次初始化的方法,是线程安全的。
  2. LazyThreadSafetyMode.PUBLICATION:如果有多个线程同时调用,会多次调用初始化的方法,但是只有第一个返回的值才会作为委托属性的值。
  3. LazyThreadSafetyMode.NONE:这种模式没有考虑多线程的情况,不应该在多线程的情况下使用。

Android中,我们一般使用的是by lazy {}

public actual fun <T> lazy(initializer: () -> T): Lazy<T> = SynchronizedLazyImpl(initializer)

这种情况属于LazyThreadSafetyMode.SYNCHRONIZED,他会使用双重锁检查初始化属性,但是Android中大部分都在UI线程属于线程安全的,如果仍然使用此模式,就会对性能有一定的影响,我们可以指定他的modeLazyThreadSafetyMode.NONE,从而减少不必要的性能开销。

val lazyValue by lazy(LazyThreadSafetyMode.NONE) {
    "lazy"
}