首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Java有惰性计算吗?

Java有惰性计算吗?
EN

Stack Overflow用户
提问于 2013-03-04 02:31:59
回答 8查看 40.6K关注 0票数 32

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

代码语言:javascript
运行
复制
public boolean isTrue() {
    boolean a = false;
    boolean b = true;
    return b || (a && b); // (a && b) is not evaluated since b is true
}

但是如果这样呢:

代码语言:javascript
运行
复制
public boolean isTrue() {
    boolean a = isATrue();
    boolean b = isBTrue();
    return b || a;
}

即使isBTrue()返回true,也会调用isATrue()吗?

EN

回答 8

Stack Overflow用户

发布于 2013-03-04 02:34:58

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

如果您将该函数重写为:

代码语言:javascript
运行
复制
public boolean isTrue() {
    return isBTrue() || isATrue();
}

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

但这是短路评估,而不是懒惰评估。懒惰的评估案例看起来像这样:

代码语言:javascript
运行
复制
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.
}
票数 32
EN

Stack Overflow用户

发布于 2013-05-31 18:37:02

不,Java只对用户定义的方法进行急切的评估。正如您所注意到的,Java的一些语言构造实现了非严格计算。其他包括if?:while

我曾经在learned1上说过,对于“有懒惰的评估”的含义有一些困惑。首先,惰性评估意味着按需调用评估。Java根本没有这样的东西。然而,有一个共同的趋势(我个人不鼓励)是放松懒惰评估的定义,以包括按名称调用的评估。在按需要调用和按名称调用的评估下,不能区分诸如&&之类的函数;无论如何,它都是一样的,这就掩盖了问题。

考虑到这种松散,一些人进一步反驳说,Java有以下懒惰的评估:

代码语言:javascript
运行
复制
interface Thunk<A> {
  A value();
}

然后,您可以编写用户定义的&&,如下所示:

代码语言:javascript
运行
复制
boolean and(boolean p, Thunk<Boolean> q) {
  return p && q();
}

然后提出声明,这表明Java具有惰性评估。然而,即使是在松散的意义上,这也不是懒惰的评估。这里的不同之处在于,Java的类型系统没有统一boolean/BooleanThunk<Boolean>类型。试图使用一个作为另一个将导致类型错误。在没有静态类型系统的情况下,代码仍然会失败。正是缺乏统一性(静态类型或非静态类型)回答了这个问题;不,Java没有用户定义的惰性计算。当然,它可以像上面那样被模拟,但这是从图灵等价中得出的一个无趣的观察结果。

诸如Scala之类的语言具有按名称调用的计算,它允许用户定义的and函数相当于常规的&&函数(考虑到终止。请参见1)。

代码语言:javascript
运行
复制
// note the => annotation on the second argument
def and(p: Boolean, q: => Boolean) =
  p && q

这允许:

代码语言:javascript
运行
复制
def z: Boolean = z
val r: Boolean = and(false, z)

请注意,这个简短的程序片段通过提供一个值来终止。它还将Boolean类型的值统一为call-by-name。因此,如果您赞同延迟计算的松散定义(同样,我不鼓励这样做),您可能会说Scala有延迟计算。我在这里提供Scala作为一个很好的对比。我推荐使用Haskell进行真正的惰性评估(call-by-need)。

希望这能有所帮助!

1

票数 17
EN

Stack Overflow用户

发布于 2014-09-27 22:40:33

SE8 (JDK1.8)引入了Lambda expressions,它可以使惰性评估更加透明。考虑以下代码的main方法中的语句:

代码语言:javascript
运行
复制
@FunctionalInterface
public interface Lazy<T> {
   T value();
}

class Test {
   private String veryLongMethod() {
      //Very long computation
      return "";
   }

   public static <T> T coalesce(T primary, Lazy<T> secondary) {
      return primary != null? primary : secondary.value();
   }

   public static void main(String[] argv) {
      String result = coalesce(argv[0], ()->veryLongMethod());
   }
}

调用的函数coalesce返回第一个给定的非空值(就像在SQL中一样)。其调用中的第二个参数是一个Lambda表达式。只有当argv ==为空时,才会调用veryLongMethod()方法。在这种情况下,惟一的有效负载是在按需延迟计算的值之前插入()->

票数 12
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15189209

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档