当前位置: 移动技术网 > IT编程>开发语言>Java > 学到ArrayList.forEach(System.out::println)我人傻了

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

2020年11月12日  | 移动技术网IT编程  | 我要评论
运行以下代码: 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

运行以下代码:

    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

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网