前言
我们经常能看到这样的代码
list.foreach(System.out::println)
下面将会解释改代码的含义
System.out::println是什么
- 首先我们来看看System.out::println到底是个什么东西!
- 既然他是foreach方法的参数,那它一定是一个对象
- 我们使用idea发现他是一个Consumer类型的对象
- ctrl+click点进去,我们发现Consumer是个接口,有accept()和andThen两个方法
- accept就是传一个参数执行一段代码,没有返回值
- andThen就是传一个Consumer,返回一个Consumer
- 因此System.out::println就是一个是实现了Consumer对象,有一个accept和andThen方法的对象,而andThen是一个被default修饰的方法,可以不继承
System.out::println的accept方法是什么?
System.out::println 等价于
x -> { System.out.println(x) } 等价于
class TestConsumer<T> implements Consumer{
@Override
public void accept(Object o) {
System.out.println(o);
}
@Override
public Consumer<T> andThen(Consumer after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
System.out::println的accept方法就是::前面的System.out调用::后面的println,参数是accept传过来的参数。
list.foreach(System.out::println)干了什么?
- 我们来看看foreach的源码
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
Objects.requireNonNull(action);这行代码是判断acction是否为null,为null就抛空指针异常和我们现在讨论的点无关,忽视它
接下来程序用超级for循环,每一次调用action的accept方法,传参为list(this)的每一个元素
也就是说foreach就是把所有的元素遍历了一遍,并调用accept方法,而accept方法是什么,他就是System.out.println(t);
总结
- System.out::println 是一个Consumer类型的对象,他的accept方法就是==::前面的对象调用::后面的方法==,即System.out.println();
- foreach方法遍历了每一个元素,并调用了System.out::println的accept方法