你是否会疑惑 list 遍历的时候 就这么一行是怎么做到的如此神奇?
List<String> al = Arrays.asList("a", "b", "c", "d");
al.forEach(System.out::println); //神奇连元素我都没传进来怎么做到遍历的??
从源码上分析:
点击进入方法源码:
可以看到,此方法来自顶级接口Iterable ,forEach 方法体中 for(T t: this) 这显然是在遍历我们每一个元素呀!所以我们现在弄清楚 for循环中 action.accept(t) 对我们list 中的每个元素干了啥,!!
首先从入参开始分析
1 forEach 方法入参规定:Consumer<? super T> action
2 Consumer 接口是功能接口,是被@FunctionalInterface 标注的 这个接口的模板是消费的意思,传参返回空代表消费 ,accept方法, 只要调用的方法[这里说的方法是指,System.out.println(String x),你看这个方法是不是符合 Consumer 接口待实现的方法 void accept(T t); 的模板样式,都是入参并且返回void,]符合待实现方法accept模板就可以,并且 :: 代表调用某个类的静态方法 ,意思是调用的方法被作为 Consumer 接口的实现, 这里还要知道注解@FunctionalInterface保证了接口有且仅有一个抽象方法,所以jdk能匹配到相应的 方法。
3 还要知道 forEach 入参的类型是 Consumer 和 使用:: 关键字后直接给转成对应的Consumer接口类型了(我猜测)
总结 : forEach 正常思维应该输入Consumer的接口实例,然后在写具体的待实现方法,但是我直接把待实现的方法具体传过去
等于说我不是在传参,而是传递一种行为,传递一个函数!!而且System.out::println 就是在调用一个方法 调用System.out.println(String x),所以就是System.out.println(String x) 方法作 为参数传递给forEach,而由于Consumer 只有一个待实现的方法,所以jdk 知道这个函数一定是传给唯一的待实现方法的具体实现。
public class MyTest {
public static void printValur(String str) {
System.out.println("print value : " + str);
}
public static void main(String[] args) {
List<String> al = Arrays.asList("a", "b", "c", "d");
al.forEach(System.out::println);//==========与下面等同=================
//==========与下面等同=================
System.out.println("===================================");
for (String a : al) {
MyTest.printValur(a);
}
/* 解释:1 forEach 方法是list的顶级接口的Iterable 接口定义的方法,入参规定:Consumer<? super T> action
2 Consumer 接口是功能接口,是被@FunctionalInterface 标注的 这个接口的模板是消费的意思,传参返回空代表消费 ,accept方法
3 只要调用的方法[这里说的方法是指,printValur(String),你看这个方法是不是符合 Consumer 接口待实现的方法 void accept(T t);
的模板样式,都是入参并且返回void
,]符合待实现方法accept模板就可以,并且 :: 代表调用某个类的静态方法 ,意思是调用的方法被作为 Consumer 接口的实现,
这里还要知道注解@FunctionalInterface保证了接口有且仅有一个抽象方法,所以jdk能匹配到相应的 方法
4 还要知道 forEach 入参的类型是 Consumer 和 使用:: 关键字后直接给转成对应的Consumer接口类型了(我猜测)
*/
System.out.println("===================================");
// forEach 正常思维应该出入Consumer的接口实例,然后在写具体的待实现方法,但是我直接把待实现的方法具体传过去
//等于说我不是在传参,而是传递一种行为,传递一个函数!!而且MyTest::printValur 就是在调用一个方法,所以就是方法作为参数传递给forEach,
//而由于Consumer 只有一个待实现的方法,所以jdk 知道这个函数一定是传给唯一的待实现方法的具体实现。
al.forEach(MyTest::printValur);
//下面的方法和上面等价的=====================================
Consumer<String> methodParam = MyTest::printValur; //方法参数
// 1 lambda 表达式 也是对接口只有一个需要实现的方法 作用,
al.forEach(x -> methodParam.accept(x));//方法执行accept
}
}