zhuanlan.zhihu.com/p/33253953 www.cnblogs.com/IcanFixIt/p… juejin.im/post/597829…
判断一个操作是惰性求值还是及早求值很简单:只需看它的返回值。如果返回值是 Stream, 那么是惰性求值;如果返回值是另一个值或为空,那么就是及早求值。使用这些操作的理 想方式就是形成一个惰性求值的链,最后用一个及早求值的操作返回想要的结果,这正是 它的合理之处。计数的示例也是这样运行的,但这只是最简单的情况:只含两步操作。 整个过程和建造者模式有共通之处。建造者模式使用一系列操作设置属性和配置,最后调 用一个 build 方法,这时,对象才被真正创建。 读者一定会问:“为什么要区分惰性求值和及早求值?”只有在对需要什么样的结果和操 作有了更多了解之后,才能更有效率地进行计算。例如,如果要找出大于 10 的第一个数 字,那么并不需要和所有元素去做比较,只要找出第一个匹配的元素就够了。这也意味着 可以在集合类上级联多种操作,但迭代只需一次。
| 接口 | 参数 | 返回类型 | 示例 |
|---|---|---|---|
| Predicate | T | boolean | 这张唱片已经发行了吗 |
| Consumer | T | void | 输出一个值 |
| Function<T,R> | T | R | 获得 Artist 对象的名字 |
| Supplier | None | T | 工厂方法 |
| UnaryOperator | T | T | 逻辑非(!) |
| BinaryOperator | (T, T) | T | 求两个数的乘积(*) |
函数式接口是只有一个抽象方法的接口,用作 Lambda 表达式的类型。 函数式接口可以加上@FunctionalInterface注解,使编译器检查接口是否符合函数式接口规范,函数式接口有且仅有一个抽象方法,可以包含多个默认方法。
以函数式接口Predicate为例,可以由抽象方法 boolean test(T t)确定该函数式接口的参数为T,返回值为boolean。
@FunctionalInterface
public interface Predicate<T> {
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);
lambda表达式是一段可以传递的代码,它的核心思想是将面向对象中的传递数据变成传递行为。
java 8之前启动线程是通过匿名类的方式,设计匿名内部类的目的,就是为了方便 Java 程序员将代码作为数据传递。但是缺点在于不够简洁,可读性差。 lambda也是将代码传递给run方法,非常简洁,这也就解释了为什么函数式接口只能有一个抽象方法,因为lambda无法指定目标方法
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("start thread by anonymous class.");
}
}).start();
new Thread(() -> System.out.println("start thread by lambda.")).start();