Lambda表达式

谓词(predicate)
在数学上常常用来代表一个类似函数的东西,它接受一个参数值,并返回 true 或 false 。


你得用 for-each 循环一个个去迭代元素,然后再处理元素。我们把这种
数据迭代的方法称为外部迭代。相反,有了Stream API,你根本用不着操心循环的事情。数据处
理完全是在库内部进行的。我们把这种思想叫作内部迭代



函数式编程中的函数的主要意思是“把函数作为一等值”,不过它也常常隐含着第二层意思,即“执行时在
元素之间无互动”。



以下哪些是使用Lambda表达式的有效方式?
(1) execute(() -> {});
public void execute(Runnable r){
r.run();
}
(2) public Callable<String> fetch() {
return () -> "Tricky example ;-)";
}
(3) Predicate<Apple> p = (Apple a) -> a.getWeight();
答案:只有1和2是有效的。
第一个例子有效,是因为Lambda () -> {} 具有签名 () -> void ,这和 Runnable 中的
抽象方法 run 的签名相匹配。请注意,此代码运行后什么都不会做,因为Lambda是空的!
第二个例子也是有效的。事实上, fetch 方法的返回类型是 Callable<String> 。
Callable<String> 基本上就定义了一个方法,签名是 () -> String ,其中 T 被 String 代替
了。因为Lambda () -> "Trickyexample;-)" 的签名是 () -> String ,所以在这个上下文
中可以使用Lambda。
第三个例子无效,因为Lambda表达式 (Apple a) -> a.getWeight() 的签名是 (Apple) ->
Integer ,这和 Predicate<Apple>:(Apple) -> boolean 中定义的 test 方法的签名不同。






使用Lambda的步骤
1. 一个方法,内部实现可能是重复的类似的,但又有点区别,就可以把有区别的部分,抽象成一个函数式接口(根据代码内部逻辑,找出对应的函数式接口签名 )。
2. 给这个方法提供一个使用函数式接口参数的版本
3. 然后依据这个函数式接口抽象方法的签名,写对应的Lambda表达式作为传入参数

Java在java.util.function包中已经提供了几个函数式接口:
1. predicate<T>返回boolean
2. Consumer<T>返回void
3. Function<T,R>返回R
Java 8中的常用函数式接口
函数式接口
函数描述符
原始类型特化
Predicate<T>
T->boolean
IntPredicate,LongPredicate, DoublePredicate
Consumer<T>
T->void
IntConsumer,LongConsumer, DoubleConsumer
Function<T,R>
T->R
IntFunction<R>,
IntToDoubleFunction,
IntToLongFunction,
LongFunction<R>,
LongToDoubleFunction,
LongToIntFunction,
DoubleFunction<R>,
ToIntFunction<T>,
ToDoubleFunction<T>,
ToLongFunction<T>
Supplier<T>
()->T
BooleanSupplier,IntSupplier, LongSupplier,
DoubleSupplier
UnaryOperator<T>
T->T
IntUnaryOperator,
LongUnaryOperator,
DoubleUnaryOperator
BinaryOperator<T>
(T,T)->T
IntBinaryOperator,
LongBinaryOperator,
DoubleBinaryOperator
BiPredicate<L,R>
(L,R)->boolean

BiConsumer<T,U>
(T,U)->void
ObjIntConsumer<T>,
ObjLongConsumer<T>,
ObjDoubleConsumer<T>
BiFunction<T,U,R>
(T,U)->R
ToIntBiFunction<T,U>,
ToLongBiFunction<T,U>,
ToDoubleBiFunction<T,U>




Java 8的Lambda和匿名类可以做类似于闭包的事情:
它们可以作为参数传递给方法,并且可以访问其作用域之外的变量。但有一个限制:它们不
能修改定义Lambda的方法的局部变量的内容。这些变量必须是隐式最终的。可以认为Lambda
是对值封闭,而不是对变量封闭。如前所述,这种限制存在的原因在于局部变量保存在栈上
并且隐式表示它们仅限于其所在线程。如果允许捕获可改变的局部变量,就会引发造成线程
不安全的新的可能性,而这是我们不想看到的(实例变量可以,因为它们保存在堆中,而堆
是在线程之间共享的)。




 






posted @ 2017-11-23 13:11  Lighters_c  阅读(236)  评论(0)    收藏  举报