Scala关键字lazy的理解和使用

Scala中使用关键字lazy来定义惰性变量,实现延迟加载(懒加载)。
惰性变量只能是不可变变量,并且只有在调用惰性变量时,才会去实例化这个变量。

在Java中,要实现延迟加载(懒加载),需要自己手动实现。一般的做法是这样的:


public class LazyDemo {

  private String property;

public String getProperty() {
  if (property == null) {//如果没有初始化过,那么进行初始化
    property = initProperty();
  }
  return property;
}

  private String initProperty() {
    return "property";
  }
}

比如常用的单例模式懒汉式实现时就使用了上面类似的思路实现。

而在Scala中对延迟加载这一特性提供了语法级别的支持:

lazy val property = initProperty()

使用lazy关键字修饰变量后,只有在使用该变量时,才会调用其实例化方法。也就是说在定义property=initProperty()时并不会调用initProperty()方法,只有在后面的代码中使用变量property时才会调用initProperty()方法。

如果不使用lazy关键字对变量修饰,那么变量property是立即实例化的:


object LazyOps {

    def init(): String = {
        println("call init()")
        return ""
    }

    def main(args: Array[String]) {
        val property = init();//没有使用lazy修饰
        println("after init()")
        println(property)
    }

}

上面的property没有使用lazy关键字进行修饰,所以property是立即实例化的,如果观察程序的输出:

call init()
after init()

可以发现,property声明时,立即进行实例化,调用了init()`实例化方法

而如果使用lazy关键字进行修饰:

object LazyOps {

    def init(): String = {
        println("call init()")
        return ""
    }

    def main(args: Array[String]) {
        lazy val property = init();//使用lazy修饰
        println("after init()")
        println(property)
        println(property)
    }

}

观察输出:

after init()
call init()

在声明property时,并没有立即调用实例化方法intit(),而是在使用property时,才会调用实例化方法,并且无论缩少次调用,实例化方法只会执行一次。

与Java相比起来,实现懒加载确实比较方便了。那么Scala是如何实现这个语法糖的呢?反编译看下Scala生成的class:

private final String property$lzycompute$1(ObjectRef property$lzy$1, VolatileByteRef bitmap$0$1)
  {
    synchronized (this)//加锁
    {
      if ((byte)(bitmap$0$1.elem & 0x1) == 0)//如果属性不为null
      {//那么进行初始化
        property$lzy$1.elem = init();bitmap$0$1.elem = ((byte)(bitmap$0$1.elem | 0x1));
      }
      return (String)property$lzy$1.elem;
    }
  }

Scala同样使用了Java中常用的懒加载的方式自动帮助我们实现了延迟加载,并且还加锁避免多个线程同时调用初始化方法可能导致的不一致问题。

借鉴崔鹏飞的小结

对于这样一个表达式: lazy val t:T = expr 无论expr是什么东西,字面量也好,方法调用也好。Scala的编译器都会把这个expr包在一个方法中,并且生成一个flag来决定只在t第一次被访问时才调用该方法。

本文的编写借鉴了剥开Scala的糖衣(5) -- Lazy

优秀的个人博客,低调大师

微信关注我们

原文链接:https://yq.aliyun.com/articles/576385

转载内容版权归作者及来源网站所有!

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

相关文章

发表评论

资源下载

更多资源
优质分享Android(本站安卓app)

优质分享Android(本站安卓app)

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

Mario,低调大师唯一一个Java游戏作品

Mario,低调大师唯一一个Java游戏作品

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Oracle Database,又名Oracle RDBMS

Oracle Database,又名Oracle RDBMS

Oracle Database,又名Oracle RDBMS,或简称Oracle。是甲骨文公司的一款关系数据库管理系统。它是在数据库领域一直处于领先地位的产品。可以说Oracle数据库系统是目前世界上流行的关系数据库管理系统,系统可移植性好、使用方便、功能强,适用于各类大、中、小、微机环境。它是一种高效率、可靠性好的、适应高吞吐量的数据库方案。

Java Development Kit(Java开发工具)

Java Development Kit(Java开发工具)

JDK是 Java 语言的软件开发工具包,主要用于移动设备、嵌入式设备上的java应用程序。JDK是整个java开发的核心,它包含了JAVA的运行环境(JVM+Java系统类库)和JAVA工具。