欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

学到ArrayList.forEach(System.out::println)我人傻了

程序员文章站 2022-04-16 19:17:33
运行以下代码: public static void main(String[] args) { List list = new ArrayList<>(); for (int i = 0; i < 10; i++) { list.add(i); } list.forEach(System.out::println);//学习这句话 }结果:0...

运行以下代码:

    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