Functional Programming in Java venkat(15): Being Lazy part2
这里是记录学习这本书 Functional Programming in Java: Harnessing the Power Of Java 8 Lambda Expressions 的读书笔记,如有侵权,请联系删除。
Lazy Evaluations
虽然Java在评估逻辑运算符时使用懒惰或正常顺序,但在评估方法参数时使用急切的顺序。在一个方法被调用之前,方法的所有参数都被完全评估。
it uses eager or applicative order when evaluating method arguments.
如果该方法没有使用所有传递的参数,那么程序就浪费了执行这些参数的时间和精力。
我们可以使用lambda表达式来延缓选择参数的执行。
While Java uses lazy or normal order when evaluating logical operators, it uses eager or applicative order when evaluating method arguments. All the arguments to methods are fully evaluated before a method is invoked. If the method doesn’t use all of the passed arguments, the program has wasted time and effort executing them. We can use lambda expressions to postpone the execution of select arguments.
Java编译器在调用的位置评估参数列表中的lambda表达式和方法引用。
然而,这些方法的调用会被推迟,直到它们被传递到的方法中明确调用。
我们可以利用这种行为,通过在lambda表达式中嵌入对方法的调用来延迟甚至避免方法的调用。
The Java compiler evaluates lambda expressions and method references in the argument list at the location of call. The invocation of these, however, is postponed until they are explicitly called from within the methods they’re passed to. We can take advantage of this behavior to delay or even avoid method invocation by embedding calls to them within lambda expressions.
JDK中的许多方法–包括Stream类上的方法–都会进行懒惰评估。
例如,filter()方法可能不会对目标集合中的所有元素调用作为参数传递的Predicate。
Quite a few methods in the JDK—including methods on the Stream class—do lazy evaluation. For instance, the filter() method may not invoke the Predicate, passed as an argument, on all the elements in the target collection
Starting with Eager Evaluation
public static boolean evaluate(final int value) {
System.out.println("evaluating ..." + value);
simulateTimeConsumingOp(2000);
return value > 100;
}
public static void simulateTimeConsumingOp(final int millseconds) {
try {
Thread.sleep(2000);
} catch(Exception ex) { throw new RuntimeException(ex); }
}
eagerEvaluator方法:Within the method we perform a logical and operation on the parameters.
public static void eagerEvaluator(
final boolean input1, final boolean input2) {
System.out.println("eagerEvaluator called...");
System.out.println("accept?: " + (input1 && input2));
}
遗憾的是,由于参数在我们进入这个方法之前就已经被评估过了,所以已经来不及从这个操作自动提供的懒惰评估中获益。
Sadly, it’s too late to benefit from the lazy evaluation this operation automatically provides since the arguments are evaluated well before we enter this method.
测试一下结果
测试代码
public static void main(final String[] args) {
System.out.println("//" + "START:EAGER_OUTPUT");
eagerEvaluator(evaluate(1), evaluate(2));
System.out.println("//" + "END:EAGER_OUTPUT");
}
输出结果
//START:EAGER_OUTPUT
evaluating ...1
evaluating ...2
eagerEvaluator called...
accept?: false
//END:EAGER_OUTPUT
如果我们运行这段代码,我们会看到在我们进入eagerEvaluator()方法之前,对evaluate()的两个调用都执行得很好。
If we run this code we’ll see both the calls to evaluate() execute well before we enter the eagerEvaluator() method.
Designing for Lazy Evaluation
如果我们知道在一个方法的执行过程中,有些参数可能不会被使用,我们可以设计它的接口以方便延迟执行一些或所有的参数。
If we know that some arguments may not be used during the execution of a method, we can design its interface to facilitate the delayed execution of some or all arguments.
public static void lazyEvaluator(
final Supplier<Boolean> input1, final Supplier<Boolean> input2) {
System.out.println("lazyEvaluator called...");
System.out.println("accept?: " + (input1.get() && input2.get()));
}
该方法不是接收两个布尔参数,而是接收对Supplier 实例的引用。这个JDK功能接口将返回一个实例,这里是布尔值,以响应对其get()方法的调用。我们在lazyEvaluator()方法中使用的逻辑和操作将只在需要时调用get()方法。
Rather than taking two boolean parameters, the method receives references to the Supplier instances. This JDK functional interface will return an instance, Boolean in this case, in response to a call to its get() method. The logical and operation we use within the lazyEvaluator() method will invoke the get() methods only on demand.
如果我们把对evaluate()的两次调用作为参数传递给lazyEvaluator()方法,那么只有当第一次调用返回布尔值为true时,第二次调用才会被启动。
If we pass two calls to evaluate() as arguments to the lazyEvaluator() method, the second will be evaluated only if the first call returned a boolean true. Let’s run the method to see this.
调用一下
public static void main(final String[] args) {
System.out.println("//" + "START:LAZY_OUTPUT");
lazyEvaluator(() -> evaluate(1), () -> evaluate(2));
System.out.println("//" + "END:LAZY_OUTPUT");
}
测试结果
//START:LAZY_OUTPUT
lazyEvaluator called...
evaluating ...1
accept?: false
//END:LAZY_OUTPUT
在我们进入lazyEvaluator()方法之前,参数没有被评估。在上面的例子中,对evaluate()的第二次调用被跳过。
The arguments are not evaluated before we enter the lazyEvaluator() method.
The second call to evaluate() was skipped in this version.
我们上面的例子中看到了懒人评估( lazy evaluation)的成本节约。当我们必须评估大量的方法,或者方法评估很耗费时间/资源时,这种技术就相当有帮助。
We saw the cost savings of the lazy evaluation. This technique is quite helpful when we have to evaluate a large number of methods or if method evaluations are time/resource consuming.