崔鹏飞的Octopress Blog

剥开Scala的糖衣(5) -- Lazy

| Comments

Scala中的lazy关键字是实现延迟加载的好帮手。

在Java中想要做到延迟加载,常规的做法是大抵是这样的:

1
2
3
4
5
6
7
8
private String str = null;

public String getStr() {
    if (str == null) {
        str = getStrFromWebService();
    }
    return str;
}

以这种方式来保证web service不会被无谓的重复请求。

C#中则可以使用Lazy of T来实现类似的事:

1
2
3
4
5
6
7
8
9
private Lazy<String> str = new Lazy<string> (() => GetStrFromWebService ());

public String Str
{
  get
  {
      return str.Value;
  }
}

Lazy of T保证传入其中的Func只执行一次。

(其实,Java也可以使用Guava中的memoize来实现类似的事情)

要么自己写代码,要么通过库来实现。

而Scala则在语言级别给出了解决方案:

1
lazy val str = getStrFromWebService()

仅此一行。

只要用lazy关键字修饰一下str,延迟执行的事就搞定了。

其实Scala编译器做的事情和我们手动做的区别不大:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  private String str;
  private volatile boolean bitmap$0;

  private String str$lzycompute()
  {
    synchronized (this) {
      if (!this.bitmap$0) {
          this.str = getStrFromWebService();
          this.bitmap$0 = true;
      }

      return this.str;
    }
  }

  public String str() {
    return this.bitmap$0 ? this.str : str$lzycompute();
  }

你看编译器多热心,还加了锁哦。

小小总结一下:

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

Comments