匿名内部类、lambda表达式、方法引用之间的关系
相信很多小伙伴在刚刚学习lambda表达式和方法引用时,都多多少少会有一点懵,这些奇奇怪怪的符号是什么,这里我和大伙一起来试着理解一下,我们用一个forEach方法来理解。
forEach
方法是Java集合框架中的一个方法,用于对集合中的每个元素执行指定的操作,假如我们有一个list集合需要遍历输出,我们就可以使用该方法,最开始我们是这样写的:
假设我们有一个Student类的集合:
List<Student> students = List.of(
new Student("高锰酸钾",20,"男"),
new Student("云悠悠",3,"女"),
new Student("司空震",30,"男"),
new Student("卡密尔",18,"女")
);
最原始的方法就是给forEach方法传递一个匿名内部类:
students.forEach(new Consumer<Student>() {
@Override
public void accept(Student student) {
System.out.println(student);
}
});
便可以得到遍历结果:
Student{name='高锰酸钾', age=20, sex='男'}
Student{name='云悠悠', age=3, sex='女'}
Student{name='司空震', age=30, sex='男'}
Student{name='卡密尔', age=18, sex='女'}
因为他需要我们传递一个Consumer接口类型的实现类,所以我们就传递一个匿名内部类来实现这个接口内的accept方法,我们点进这个接口会发现:
这个接口的上方有一个@FunctionalInterface
注解,他的意思是声明这是一个函数式接口,函数式接口是指只包含一个抽象方法的接口,而在Java 8 引入了函数式接口的概念,就是为了支持Lambda表达式和方法引用这类函数式编程的特性。
那么显而易见,我们可以用lambda表达式简化这个函数式接口的传参,不必再为他创建一个匿名内部类再重写方法了:
students.forEach((student -> System.out.println(student)));
箭头前面是传递的参数,箭头后是行为方法,这是对应关系:
到了这一步,我们发现Lambda表达式的主体是调用了输出方法,并且没有其他的逻辑,而方法引用的作用是:
如果某个Lambda表达式的主体是调用某个已有方法,并且没有其他的逻辑,那么可以使用方法引用来代替Lambda表达式,从而使代码更加简洁和易读。
此时我们的代码就可以改造为:
students.forEach(System.out::println);
这是一个静态方法引用::
前面的部分表示类名或者对象名,后面的部分表示方法名
我们同样可以得到输出结果:
Student{name='高锰酸钾', age=20, sex='男'}
Student{name='云悠悠', age=3, sex='女'}
Student{name='司空震', age=30, sex='男'}
Student{name='卡密尔', age=18, sex='女'}
这样这个遍历输出的方法就被我们从匿名内部类、lambda表达式再到方法引用一步步的简化了,从简化过程我们可以大致理解他们的作用和意义~