可以把Lambda表达式理解为简洁地表示可传递的匿名函数的一种方式:它没有名称,但它有参数列表、函数主体、返回类型,可能还有一个可以抛出的异常列表。 Lambda表达式由参数、箭头和主体组成
1 、(String s) -> s.length() :该Lambda表达式具有一个String类型的参数并返回一个int。 Lambda没有return语句,因为已经隐含了return。
2、(User a) -> a.getWeight() > 150:改Lambda表达式有一个Apple类型的参数并返回一个boolean(人的体重是否超过150克)。
3、具有两个int类型的参数而没有返回值(void返回)。注意Lambda表达式可以包含多行语句,这里是两行。
4、() -> 12 :Lambda 表达式没有参数,返回一个int
5、Lambda表达式语法示例:Lambda表达式具有两个User类型的参数,返回一个int:比较两个User的体重。
以前的字符串排序:
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class ClassC implements InterfaceA,InterfaceB{
public static void main(String[] args) {
List<String> names = Arrays.asList("A", "B", "C", "D");
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String a, String b) {
return b.compareTo(a);
}
});
System.out.println(names.toString());
}
}
Java 8 Lambda 更加简洁
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class ClassC implements InterfaceA,InterfaceB{
public static void main(String[] args) {
List<String> names = Arrays.asList("A", "B", "C", "D");
Collections.sort(names, (a, b) -> b.compareTo(a));
System.out.println(names.toString());
}
}
Java 编译器可以自动推导出参数类型,不需要再多写类型。
函数式接口就是只定义一个抽象方法的接口,Lambda表达式允许直接以内联的形式为函数式接口的抽象方法提供实现,并把整个表达式作为函数式接口的实例 。也就是说,默认方法不算抽象方法,所以可以给函数式接口添加默认方法。
Runnabel r1 = () -> System.out.println("Hello world one");
# 注意:使用lambda表达式
Runnable r2 = new Runnable(){
public viod run(){
System.out.println("Hello world two");
}
}
# 注意:使用匿名类
public static void process(Runnable r){
r.run();
}
process(r1); #打印“Hello world one”
process(r2); #打印“Hello world two”
process(() -> System.out.println("Hello world three") ); #利用直接传递的lambda打印“Hello world three”
这个标注用于表示该接口会设计成一个函数式接口。如果你用@FunctionalInterface定义了一个接口,而它却不是函数式接口的话,编译器将返回一个提示原因的错误。
@FunctionalInterface不是必需的,但对于为此设计的接口而言,使用它是比较好的做法
注意:如果@FunctionalInterface如果没有指定,上面的代码也是对的。
@FunctionalInterface
public interface Coverter<F, T> {
T convert(F from);
}
public class CoverterClass {
public static void main(String[] args) {
Coverter<String, Integer> converter = (from) -> Integer.valueOf(from);
Integer converted = converter.convert("123");
System.out.println(converted); // 123
}
}
函数式接口 | 函数描述符 | 原始类型特化 |
---|---|---|
Predicate |
T -> boolean | IntPredicate LongPredicate DoublePredicate |
Consumer |
T -> void | IntConsumer LongConsumer DoubleConsumer |
Function<T, R> | T -> R | IntFunction IntToDoubleFunction IntToLongFunction LongFunction LongToDoubleFunction LongToIntFunction DoubleFunction ToIntFunction ToDoubleFunction ToLongFunction |
Supplier |
() -> T | BooleanSupplier IntSupplier LongSupplier DoubleSupplier |
UnaryOperator |
T -> T | IntUnaryOperator LongUnaryOperator DoubleUnaryOperator |
BinaryOperator |
(T, T) -> T | IntBinaryOperator LongBinaryOperator DoubleBinaryOperator |
BiPredicate<L, R> | (L, R) -> boolean | |
BiConsumer<T, U> | (T, U) -> void | ObjIntConsumer ObjLongConsumer ObjDoubleConsumer |
BiFunction<T, U, R> | (T, U) -> R | ToIntBiFunction<T, U> ToLongBiFunction<T, U> ToDoubleBiFunction<T, U> |
自定义函数式接口
@FunctionalInterface
public interface MyFunction<T, R, U> {
Boolean test(T t, R r, U u);
}
闭包就是一个函数的实例,且它可以无限制地访问那个函数的非本地变量。例如,闭包可以作为参数传递给另一个函数。它也可以访问和修改其作用域之外的变量。
Java 8的Lambda和匿名类可以做类似于闭包的事情,但有一个限制:它们不能修改定义Lambda的方法的局部变量的内容。这些变量必须是隐式final的。可以认为Lambda是对值封闭,而不是对变量封闭。这种限制存在的原因在于局部变量保存在栈上,并且隐式表示它们仅限于其所在线程。如果允许捕获可改变的局部变量,就会引发造成线程不安全的新的可能性。
1)、Java 8的设计者决定允许方法作为值,让编程更轻松。此外,让方法作为值也构成了其他若干Java 8功能(如Stream)的基础。
2)、方法引用可以被看作仅仅调用特定方法的Lambda的一种快捷写法。它的基本思想是,如果一个Lambda代表的只是“直接调用这个方法”,那最好还是用名称来调用它,而不是去描述如何调用它。
|Lambda |等效的方法引用|
|---|---|
|(Apple a ) -> a.getWeight|Apple::getWeight|
|() ->Thread.currentThread().dumpStack()|Thread.currentThread()::dumpStack|
|(str,i) ->str.substring(i)|String::substring|
|String s -> System.out.println(s)|System.out::println|
3)、引用方法举例
将方法引用File::isHidden传递给listFiles方法
常用的复合表达式:Comparator、Predicate、Function三种复合表达式
1)、比较器复合
2)、谓词复合
3)、函数复合
本文作者:魂皓轩 欢迎关注公众号
本人保留所有权益,转载请注明出处。
欢迎有故事、有想法的朋友和我分享,可发送至 e-mail: lwqforit@163.com
原文:https://www.cnblogs.com/lwqforit/p/11997896.html