原来 Lamda 表达式是这样写的

作者:微信小助手

发布时间:2021-11-05T09:27:20

Lamda 表达式非常方便,在项目中一般在 stream 编程中用的比较多。
List<Student> studentList = gen();
Map<String, Student> map = studentList .stream()
        .collect(Collectors.toMap(Student::getId, a -> a, (a, b) -> a));
理解一个 Lamda 表达式就三步:

1. 确认 Lamda 表达式的类型

2. 找到要实现的方法

3. 实现这个方法

 
就这三步,没其他的了。而每一步,都非常非常简单,以至于我分别展开讲一下,你就懂了。
 

确认 Lamda 表达式的类型

 

能用 Lamda 表达式来表示的类型,必须是一个函数式接口,而函数式接口,就是只有一个抽象方法的接口。
 
我们看下非常熟悉的 Runnable 接口在 JDK 中的样子就明白了。
 
@FunctionalInterface
public interface Runnable {
    public abstract void run();
}
这就是一个标准的函数式接口。

因为只有一个抽象方法。而且这个接口上有个注解
@FunctionalInterface
这个仅仅是在编译期帮你检查你这个接口是否符合函数式接口的条件,比如你没有任何抽象方法,或者有多个抽象方法,编译是无法通过的。
// 没有实现任何抽象方法的接口
@FunctionalInterface
public interface MyRunnable {}

// 编译后控制台显示如下信息
Error:(31) java: 
  意外的 @FunctionalInterface 注释
  MyRunnable 不是函数接口
    在 接口 MyRunnable 中找不到抽象方法

再稍稍复杂一点,Java 8 之后接口中是允许使用 默认方法 静态方法 的,而这些都不算抽象方法,所以也可以加在函数式接口里。
 
看看你可能不太熟悉又有点似曾相识的一个接口。
@FunctionalInterface
public interface Consumer<T{
    void accept(T t);
    default Consumer<T> andThen(Consumer<? super T> after) {...}
}
看,只有一个抽象方法,还有一个默认方法(方法体的代码省略了),这个也不影响它是个函数式接口。再看一个更复杂的,多了静态方法,这同样也是个函数式接口,因为它仍然只有一个抽象方法。自行体会吧。
@FunctionalInterface
public interface Predicate<T{
    boolean test(T t);
    
    default Predicate<T> and(Predicate<? super T> other) {...}
    default Predicate<T> negate() {...}
    default Predicate<T> or(Predicate<? super T> other) {...}
    
    static <T> Predicate<T> isEqual(Object targetRef) {...}
    static <T> Predicate<T> not(Predicate<? super T> target) {...}
}
先不用管这些方法都是干嘛的,这些类在 Stream 设计的方法中比比皆是,我们就先记住这么一句话, Lamda 表达式需要的类型为函数式接口,函数式接口里只有一个抽象方法 ,就够了,以上三个例子都属于函数式接口。
 
恭喜你,已经学会了 Lamda 表达式最难的部分,就是认识函数式接口。
 

找到要实现的方法


 
Lamda 表达式就是实现一个方法,什么方法呢?就是刚刚那些函数式接口中的抽象方法