学到ArrayList.forEach(System.out::println)我人傻了
程序员文章站
2022-04-16 19:17:33
运行以下代码: public static void main(String[] args) { List
运行以下代码:
public static void main(String[] args) {
List<Object> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(i);
}
list.forEach(System.out::println);//学习这句话
}
结果:
0
1
2
3
4
5
6
7
8
9
思考思路
一脸懵逼,毫无思路,先看源码
分析源码
forEach方法源码
- 传入参数是Consumer<? super E>
- ArrayList中的元素一个一个action.accept();
//java.util.ArrayList
@Override
public void forEach(Consumer<? super E> action) {
Objects.requireNonNull(action);
final int expectedModCount = modCount;
@SuppressWarnings("unchecked")
final E[] elementData = (E[]) this.elementData;
final int size = this.size;
for (int i=0; modCount == expectedModCount && i < size; i++) {
action.accept(elementData[i]); //重点在这!!!
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
问题:
- 1.Consumer是个啥?
- 2.action.accept做了什么?
Consumer源码
- Consumer是一个接口(问题一)
- @FunctionalInterface标记在接口上, “函数式接口”是指仅仅只包含一个抽象方法的接口。这个仅有一个accept(T t)抽象方法
- Consumer<T> 泛型
//java.util.function
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
源码看到这,发现foreach里面传的是一个Consumer,用new的方式新建一个Consumer对象(实现接口的匿名类),然后传人forEach里面
public static void main(String[] args) {
List<Object> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(i);
}
Consumer<Object> consumer = new Consumer<Object>()
{
//(问题二)
@Override
public void accept(Object o) {
System.out.println(o);
}
};//实现接口的匿名类
list.forEach(consumer);
//list.forEach(System.out::println);
}
结果和最初一样。
但是在Java8后,支持Lamdba表达式,所以实现接口的匿名类可以这么写(Lamdba表达式也可以直接方到forEach()中)
public static void main(String[] args) {
List<Object> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(i);
}
Consumer<Object> consumer = s-> System.out.println(s);//Lamdba表达式
list.forEach(consumer);
//list.forEach(s-> System.out.println(s));//Lamdba表达式可以直接做参数
//list.forEach(System.out::println);
}
System对象里有个PrintStream对象的静态引用out , System.out
对象PrintStream里面有println方法, System.out::out
containingObject::instanceMethodName表示引用特定对象的实例方法 这里是:java.io.PrintStream::println
public static void main(String[] args) {
List<Object> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(i);
}
PrintStream out = System.out;
Consumer<Object> consumer = out::println; //LamdbaTest$$Lambda$3/1023892928 consumer在这里不是一个值,而是一个Lamdba表达式
list.forEach(consumer);
}
这样就分析完成了
本文地址:https://blog.csdn.net/qq_33835370/article/details/109642448