目录

Kotlin系列(二十四):秘技之延迟属性


一、前言:

  • 我们在上一篇学习了Kotlin的委托属性的使用及原理。
  • 本章我们将学习基于委托属性而演变出来的非常使用的一个属性-延迟属性;
  • 延迟属性也是Kotlin标准库中提供的工厂方法之一;

二、延迟属性: Lazy

  • 用法很简单,你只需要记住Lazy关键字即可。

  • lazy() 是接受一个 lambda 并返回一个 Lazy <T> 实例的函数,返回的实例可以作为实现延迟属性的委托:

  • 第一次调用 get() 会执行已传递给 lazy() 的 lambda 表达式并记录结果,后续调用 get() 只是返回记录的结果。

  • 测试代码如下

      val lazyValue: String by lazy {
      	println("computed!")
      		"Anjie"
      }
    
      @Test
      fun test1() {
      		println(lazyValue)
      		println(lazyValue)
      }
    
  • 结果输出为:

      computed!
      Anjie
      Anjie
    
  • 默认情况下,对于 lazy 属性的求值是同步锁的(synchronized):该值只在一个线程中计算,并且所有线程会看到相同的值。

  • 如果初始化委托的同步锁不是必需的,这样多个线程可以同时执行,那么将 LazyThreadSafetyMode.PUBLICATION 作为参数传递给 lazy() 函数。

  • 而如果你确定初始化将总是发生在单个线程,那么你可以使用 LazyThreadSafetyMode.NONE 模式,它不会有任何线程安全的保证和相关的开销。

  • 懒加载的源码我们就不看了,本章节作为基础文章,太深入反而不好,但是我们可以从原理上猜测一番。

  • 1、lazy后面为什么会跟一个lambada函数呢?其实你可以把他当作闭包,这样子就很好理解了。

  • 为什么呢?因为闭包可以有自己的管理区域,其也能捕获外部变量,最主要的是,利用其延迟调用的方式似乎便可实现我们的延迟加载了。

  • 2、根据前面对委托属性的分析,我们大可假设,当我们调用延迟属性的时候,其getter内部会调用一个代理类的某个方法,该代理类是kotlin自动生成,且与lazy有关,所以代理类掌握着我们的lambada函数。

  • 3、其内部可以做判断,当我们第一次调用时,其就执行lambada函数并记录返回的值,当下次调用时,直接返回即可。

  • 4、当然,当多个线程同时调用时,是否就混乱了呢?所以kotlin为我们提供了默认的线程安全的配置,当然你也可以根据自己的实际情况来配置为线程非安全的。

  • 以上便是我大胆而不实际的猜测,感谢您的观看。