美文网首页Scala编程与实践Scala简明速学
Scala关键字lazy的理解和使用

Scala关键字lazy的理解和使用

作者: volkin | 来源:发表于2016-08-12 18:19 被阅读680次

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

相关文章

  • Scala关键字lazy的理解和使用

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

  • swift3.0 - 懒加载

    和OC不同的是swift有专门的关键字来实现懒加载 lazy关键字可以用于定义某一个属性懒加载 格式: lazy ...

  • scala教程之:可见性规则

    和java很类似,scala也有自己的可见性规则,不同的是scala只有private和protected关键字,...

  • 自己实现swift lazy关键字效果

    Lazy lazy关键字的作用是在第一次使用属性的时候才去生成,而不是在一开始就初始化好,按需使用。当计算属性的值...

  • Scala-4.控制结构-break和continue

    Scala中没有break和continue这两个关键字,而是以scala.util.control.Breaks...

  • 【kotlin】委托

    在 kotlin 开发中,会遇到懒加载的情形:使用 by lazy 关键字。而这是通过委托来实现的。Kotlin ...

  • 2020-11-10-Scala-30(scala中文版的摘录1

    怎么使用scala中的构造器(避免使用java的方式思考) 怎么理解scala中的pojo 1.不可变对象的权衡 ...

  • 2018-11-14号相关学习资料

    java中final关键字的作用深入理解Java中的final关键字java中的final如何使用和理解PPT和1...

  • SPARK的学习

    Spark着重学习这几点: scala 语言 Spark编程RDD 的理解使用DStream 的理解与使用 sca...

  • Scala如何实现break和continue

    Scala中没有Java/C/C++中的break和continue这样的关键字来控制循环,而我们在写Scala/...

网友评论

    本文标题:Scala关键字lazy的理解和使用

    本文链接:https://www.haomeiwen.com/subject/roresttx.html