我知道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;
}
即使isBTrue()
返回true,也会调用isATrue()
吗?
发布于 2013-03-04 02:34:58
嗯,就语言而言--是的,两个函数都被调用了。
如果您将该函数重写为:
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.
}
发布于 2013-05-31 18:37:02
不,Java只对用户定义的方法进行急切的评估。正如您所注意到的,Java的一些语言构造实现了非严格计算。其他包括if
,?:
,while
。
我曾经在learned1上说过,对于“有懒惰的评估”的含义有一些困惑。首先,惰性评估意味着按需调用评估。Java根本没有这样的东西。然而,有一个共同的趋势(我个人不鼓励)是放松懒惰评估的定义,以包括按名称调用的评估。在按需要调用和按名称调用的评估下,不能区分诸如&&
之类的函数;无论如何,它都是一样的,这就掩盖了问题。
考虑到这种松散,一些人进一步反驳说,Java有以下懒惰的评估:
interface Thunk<A> {
A value();
}
然后,您可以编写用户定义的&&
,如下所示:
boolean and(boolean p, Thunk<Boolean> q) {
return p && q();
}
然后提出声明,这表明Java具有惰性评估。然而,即使是在松散的意义上,这也不是懒惰的评估。这里的不同之处在于,Java的类型系统没有统一boolean
/Boolean
和Thunk<Boolean>
类型。试图使用一个作为另一个将导致类型错误。在没有静态类型系统的情况下,代码仍然会失败。正是缺乏统一性(静态类型或非静态类型)回答了这个问题;不,Java没有用户定义的惰性计算。当然,它可以像上面那样被模拟,但这是从图灵等价中得出的一个无趣的观察结果。
诸如Scala之类的语言具有按名称调用的计算,它允许用户定义的and
函数相当于常规的&&
函数(考虑到终止。请参见1)。
// note the => annotation on the second argument
def and(p: Boolean, q: => Boolean) =
p && q
这允许:
def z: Boolean = z
val r: Boolean = and(false, z)
请注意,这个简短的程序片段通过提供一个值来终止。它还将Boolean
类型的值统一为call-by-name。因此,如果您赞同延迟计算的松散定义(同样,我不鼓励这样做),您可能会说Scala有延迟计算。我在这里提供Scala作为一个很好的对比。我推荐使用Haskell进行真正的惰性评估(call-by-need)。
希望这能有所帮助!
1
发布于 2014-09-27 22:40:33
SE8 (JDK1.8)引入了Lambda expressions,它可以使惰性评估更加透明。考虑以下代码的main方法中的语句:
@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()方法。在这种情况下,惟一的有效负载是在按需延迟计算的值之前插入()->
。
https://stackoverflow.com/questions/15189209
复制相似问题