Java有惰性评估吗?

2022-09-01 07:11:29

我知道Java在这种情况下有智能/懒惰的评估:

public boolean isTrue() {
    boolean a = false;
    boolean b = true;
    return b || (a && b); // (a && b) is not evaluated since b is true
}

但是:

public boolean isTrue() {
    boolean a = isATrue();
    boolean b = isBTrue();
    return b || a;
}

即使返回 true,是否被调用?isATrue()isBTrue()


答案 1

好吧,就语言而言 - 是的,两个函数都被调用。

如果将函数重写为:

public boolean isTrue() {
    return isBTrue() || isATrue();
}

则第二个函数将不会被调用,如果第一个函数为真。


但这是短路评估,而不是懒惰评估。惰性求值情况将如下所示:

public interface LazyBoolean {
    boolean eval();
}

class CostlyComparison implements LazyBoolean {
  private int a, b;

  public CostlyComparison(int a, int b) { 
    this.a=a; 
    this.b=b; 
  }

  @Override 
  public boolean eval() {
    //lots of probably not-always-necessary computation here
    return a > b;
  }
} 

public LazyBoolean isATrue() {
  return new CostlyComparison(10,30);  //just an example
}

public boolean isTrue() {        // so now we only pay for creation of 2 objects
    LazyBoolean a = isATrue();   // but the computation is not performed; 
    LazyBoolean b = isBTrue();   // instead, it's encapsulated in a LazyBoolean
    return b.eval() || a.eval(); // and will be evaluated on demand;
                                 // this is the definition of lazy eval.
}

答案 2

在Java(和其他类似C语言)中,这被称为短路评估*

是的,在第二个示例中,总是调用。也就是说,除非编译器/JVM 可以确定它没有可观察到的副作用,在这种情况下,它可能会选择优化,但在这种情况下,您无论如何都不会注意到差异。isATrue


* 这两者是完全不同的。前者本质上是一种优化技术,而第二种是由语言强制要求的,可以影响可观察的程序行为。

我最初认为这与懒惰的评估完全不同,但正如@Ingo在下面的评论中指出的那样,这是一个可疑的断言。人们可能会将Java中的短路运算符视为惰性求值的非常有限的应用。

然而,当函数式语言要求懒惰评估语义时,它通常是出于一个完全不同的原因,即防止无限(或至少是过度)递归。