Kotlin中的延迟属性(lazy properties)

属于Kotlin中的委托属性这一章中的标准委托

延迟属性Lazy

lazy() 是接受一个lambda 并返回一个 Lazy <T> 实例的函数,返回的实例可以作为实现延迟属性的委托。也就是说:
第一次调用get() 会执行已传递给 lazy() 的 lambda 表达式并记录结果, 后续调用get() 只是返回记录的结果。

这里需要注意的是 调用的是 get()方法,和set没啥关系

val lazyValue: String by lazy {
    println("computed!")
    "Hello"
}

fun main(args: Array<String>) {
    println(lazyValue)
    println(lazyValue)
}

输出结果为

computed!
Hello
Hello

同步锁模式

防止对个线程同时初始化

默认情况下,对于 lazy 属性的求值是同步锁的(synchronized):该值只在一个线程中计算,并且所有线程会看到相同的值。如果初始化委托的同步锁不是必需的,这样多个线程可以同时执行,那么将 LazyThreadSafetyMode.PUBLICATION 作为参数传递给 lazy() 函数。 而如果你确定初始化将总是发生在单个线程,那么你可以使用 LazyThreadSafetyMode.NONE模式, 它不会有任何线程安全的保证和相关的开销。

延迟属性Lazy 与 lateinit 区别

以下是lateinit var和by lazy { ... }委托属性之间的显著差异:

  • lazy { ... }代表只能用于val属性,而lateinit只能用于var,因为它不能编译到final字段,因此不能保证不变性;
  • lateinit var具有存储值的后备字段(backing field),而by lazy { ... }创建一个委托对象,其中存储一次计算的值,将对代理实例的引用存储在类对象中,并为与委托实例一起使用的属性生成getter。
  • 除了val之外,lateinit不能用于可空属性和Java原语类型(这是因为null用于未初始化的值);所以如果你需要在类中存在的支持字段,请使用lateinit;
    lateinit var可以从对象被看到的任何地方被初始化。从一个框架代码的内部,多个初始化方案是可能的单一类的不同对象。 by lazy { ... }反过来又定义了属性的唯一初始化器,只能通过覆盖子类中的属性进行更改。如果您希望以预先未知的方式从外部初始化属性,请使用lateinit。
  • 另外,还有一个方法没有提到Delegates.notNull(),它适用于non-null属性的延迟初始化,包括Java原始类型的属性。

延迟属性Lazy 与 lateinit 使用总结

lateinit用于外部初始化:当需要外部资料通过调用方法初始化您的值时。
例如通过调用:

private lateinit var value: MyClass

fun init(externalProperties: Any) {
   value = somethingThatDependsOn(externalProperties)
}

lazy当它只使用对象内部的依赖关系时。
嗯。静态变量的初始化挺适合这种方式的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容