java 接口Iterable和Iterator 源码分析

目录

Iterator

简介

hasNext

next

remove

forEachRemaining

Iterable

iterator

forEach

spliterator

IteratorSpliterator

简介

数据结构

构造方法

tryAdvance和forEachRemaining

trySplit

其他


Iterator

简介

Iterator模式腾空出世,它总是用同一种逻辑来遍历集合。使得客户端自身不需要来维护集合的内部结构,所有的内部状态都由Iterator来维护。客户端从不直接和集合类打交道,它总是控制Iterator,向它发送"向前","向后","取当前元素"的命令,就可以间接遍历整个集合。

java 接口Iterable和Iterator 源码分析_第1张图片

在Java中Iterator为一个接口,它只提供了迭代了基本规则,在JDK中他是这样定义的:对 collection 进行迭代的迭代器。迭代器取代了 Java Collections Framework 中的 Enumeration。

/**
 * 

一个迭代器覆盖一个集合,iterator取代了enumeration * 它比enumeration好的地方是 *

允许在已经访问过的集合内,删除元素 *

增强方法的名字 * * @param the type of elements returned by this iterator *

E是迭代器返回的元素的类型 * @author Josh Bloch * @see Collection * @see ListIterator * @see Iterable * @since 1.2 */ public interface Iterator

hasNext

是否有下个元素

    /**
     * 

返回这次迭代是否还有更多的元素,换言而之,如果返回true,那么调用next方法会返回一个元素 *

如果返回false,next方法会报错 * @return {@code true} if the iteration has more elements */ boolean hasNext();

next

返回下个元素

    /**
     * Returns the next element in the iteration.
     * 

返回这次迭代的下一个元素,如果没有了,会报NoSuchElementException * @return the next element in the iteration * @throws NoSuchElementException if the iteration has no more elements */ E next();

remove

存在默认方法,删除

    /**
     * 

在已经访问过的集合内,删除最后返回的元素 *

这个方法只能在调用next方法后,被调用一次,一一对应,(不能调用1次next,然后调用2次remove) *

如果被访问的集合被修改了(当这个迭代处于其他的过程而不是通过调用这个方法),这个方法的结果没有被定义 *

例如在别的线程内,删除元素 *

默认实现是不实现方法,抛出异常UnsupportedOperationException(代表着实现iterator接口的类,可以选择不实现这个方法) * @throws UnsupportedOperationException if the {@code remove} * operation is not supported by this iterator * * @throws IllegalStateException if the {@code next} method has not * yet been called, or the {@code remove} method has already * been called after the last call to the {@code next} * method */ default void remove() { throw new UnsupportedOperationException("remove"); }

forEachRemaining

jdk1.8新增的方法,是默认方法,action执行剩余所有元素

    /**
     * 

对每个保留的元素执行给定的参数action的accept方法,直到所有的元素都被处理了或者action报错 *

注意:第一个被执行的元素是下一次next返回的元素,而不是这个迭代器被新建时,第一次next的元素 *

action以迭代的顺序被执行(如果顺序被设定了) *

被抛出的异常会被转发给调用者 *

默认实现等价于 *

{@code
     *     while (hasNext())
     *         action.accept(next());
     * }
* * @param action The action to be performed for each element * @throws NullPointerException if the specified action is null * @since 1.8 */ default void forEachRemaining(Consumer action) { Objects.requireNonNull(action); while (hasNext()) action.accept(next()); }

Iterable

Iterable是迭代器的意思,作用是为集合类提供for-each循环的支持。由于使用for循环需要通过位置获取元素,而这种获取方式仅有数组支持,其他许多数据结构,比如链表,只能通过查询获取数据,这会大大的降低效率。Iterable就可以让不同的集合类自己提供遍历的最佳方式。

它的作用就是为Java对象提供foreach循环,其主要方法是返回一个Iterator对象:

也就是说,如果想让一个Java对象支持foreach,只要实现Iterable接口,然后就可以像集合那样,通过Iterator iterator = strings.iterator()方式,或者使用foreach,进行遍历

java 接口Iterable和Iterator 源码分析_第2张图片

iterator

主要功能,通过iterator方法,返回一个iterator

    /**
     * 

返回一个iterator(T类型的) * @return an Iterator. */ Iterator iterator();

forEach

1.8新增的方法,默认方法,对iterable的所有元素作为参数执行下面的action.accept这个方法

    /**
     * 

默认方法,对iterable的所有元素作为参数执行下面的action.accept这个方法,直到抛出异常 *

除非这个方法被覆盖的方法重写了,元素以iterator的顺序被执行 *

被抛出的异常会被转发给调用者 *

这个方法等价于下面的这个代码 *

{@code
     *     for (T t : this)
     *         action.accept(t);
     * }
* * @param action iterable里的所有元素,都作为参数,一个个给action对象,然后调用它的accept方法 * @throws NullPointerException if the specified action is null * @since 1.8 */ default void forEach(Consumer action) { //先校验这个action是否为空,如果为空则报错NullPointerException Objects.requireNonNull(action); //对这个iterable对象进行foreach循环 for (T t : this) { action.accept(t); } }

spliterator

通过Spliterators工具类的spliteratorUnknownSize方法,返回一个默认的spliterator,这个应该要被覆盖

    /**
     * 

创建一个spliterator覆盖这个iterable包含的元素。 * *

默认的实现从iterable的iterator创建一个早期绑定的spliterator。 * 这个spliterator从iterable的iterator继承fail-fast属性。 * *

默认的实现应该通常被覆盖。默认实现返回的spliterator有很差的分割能力,没有报告大小,不能报告任何特征。 * 实现的类应该接近总是提供一个更好的实现。 * * @return a {@code Spliterator} over the elements described by this * {@code Iterable}. * @since 1.8 */ default Spliterator spliterator() { //用iterable的iterator结果作为参数,特征直接设置为0,啥都没有 return Spliterators.spliteratorUnknownSize(iterator(), 0); }

可以看到是用给定的iterator作为元素的来源,没有最初的大小估计,创建一个spliterator,一个IteratorSpliterator

    /**
     * 

使用给定的iterator作为元素的来源,没有最初的大小估计,创建一个spliterator。 * *

这个spliterator不是迟绑定的,基础了iterator的fail-fast属性, * 并且实现了trySplit,来允许有限的并发。 * *

元素的遍历应该通过spliterator完成。 * 如果在返回spliterator后对iterator进行操作,分割和遍历的行为是未定义的。 * * * @param Type of elements * @param iterator The iterator for the source * @param characteristics 这个spliterator的来源或元素的特征。(如果是sized和subsized,会被忽略,并且不报告) * @return A spliterator from an iterator * @throws NullPointerException if the given iterator is {@code null} */ public static Spliterator spliteratorUnknownSize(Iterator iterator, int characteristics) { return new IteratorSpliterator<>(Objects.requireNonNull(iterator), characteristics); }

IteratorSpliterator

简介

一个spliterator使用给定的iterator作为元素的操作,它实现了trySplit来允许有限的并发。

java 接口Iterable和Iterator 源码分析_第3张图片

    /**
     * 一个spliterator使用给定的iterator作为元素的操作,它实现了trySplit来允许有限的并发。
     */
    static class IteratorSpliterator implements Spliterator

数据结构

        static final int BATCH_UNIT = 1 << 10;  // batch array size increment
        static final int MAX_BATCH = 1 << 25;  // max batch array size;

        /**

collection和iterator可以在构建时2选1设置,如果是collection,最后会从它生成iterator,赋值给it,最后是使用iterator *

注意collection生成iterator,为了减少对元素来源的操作的影响,会在调用方法时(例如tryAdvance)生成,并设置est=collecion的size *

collection是否为null都可以 */ private final Collection collection; private Iterator it; //最后使用的iterator private final int characteristics; private long est; // size estimate private int batch; // batch size for splits

构造方法

        /**
         * Creates a spliterator using the given iterator
         * for traversal, and reporting the given initial size
         * and characteristics.
         * 
         *
         * @param iterator the iterator for the source
         * @param characteristics properties of this spliterator's
         * source or elements.
         */
        public IteratorSpliterator(Iterator iterator, int characteristics) {
            this.collection = null; 
            this.it = iterator;
            this.est = Long.MAX_VALUE;  //这种情况估计大小为long的max
            //特征值无视了sized和subsized(就是这两个位置都设置为0)
            this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED); 
        }

tryAdvance和forEachRemaining

基本都是利用iterator的next作为action的参数

        @Override
        public boolean tryAdvance(Consumer action) {
            if (action == null) throw new NullPointerException();
            if (it == null) {
            	//初始化iterator
                it = collection.iterator();
                est = (long) collection.size();
            }
            //it调用next,iterator前进一步,action接受next的返回值。
            if (it.hasNext()) {
                action.accept(it.next());
                return true;
            }
            return false;
        }


        @Override
        public void forEachRemaining(Consumer action) {
            if (action == null) throw new NullPointerException();
            Iterator i;
            if ((i = it) == null) {
                i = it = collection.iterator();
                est = (long)collection.size();
            }
            //使用iterator自带的forEachRemaining方法,
            i.forEachRemaining(action);
        }

trySplit

分割为等差数列,每次增加1024,next的元素放入数组,最后通过ArraySpliterator返回。

        @Override
        public Spliterator trySplit() {
            /*
             * 
             * 分割成算数上递增的块大小。这将仅仅增加并发效果,如果将每个元素进行consumer操作比将它们变成数组花费更大。
             * 分割大小递增提供了开销与并发之间的界限,这不是特别有利于或者不利于轻量级元素和重量级元素的操作,
             * 它们跨越元素多少n和cpu核心数的组合,无论两者是否已知。我们产生O(sqrt(n))的分割,允许O(sqrt(cores))的潜在递增。
             * 
             */
            Iterator i;
            //s为预计大小
            long s;
            //初始化iterator
            if ((i = it) == null) {
                i = it = collection.iterator();
                s = est = (long) collection.size();
            }
            else
                s = est;
            if (s > 1 && i.hasNext()) {
            	//如果预计大小>1并且iterator有next
            	//batch为上次分块的大小,最初为0,BATCH_UNIT为块每次递增的长度,=1024,n为本次分割的元素的长度
                int n = batch + BATCH_UNIT;
                if (n > s)
                    n = (int) s; //如果n>s,则n=s
                if (n > MAX_BATCH)
                    n = MAX_BATCH;//如果n>max_batch,则n=max_batch= 33554432 
                Object[] a = new Object[n]; //建立大小为n的数组
                int j = 0;
                //将数组a中元素一个个放置为i.next,直到没有next或者填满为止
                do { a[j] = i.next(); } while (++j < n && i.hasNext());
                batch = j; //这次块的大小为j
                if (est != Long.MAX_VALUE)
                    est -= j; //如果est存在,则减去j
                //最后根据数组a,长度0到j,特征为characteristics,构建一个ArraySpliterator
                return new ArraySpliterator<>(a, 0, j, characteristics);
            }
            return null;
        }

其他

        @Override
        public long estimateSize() {
            if (it == null) {
            	//如果是collection作为构造函数,就先生成iterator
            	//返回collection的size
                it = collection.iterator();
                return est = (long)collection.size();
            }
            //如果是iterator作为参数,会返回long.max_value
            //不然会返回上面赋给est的值
            return est;
        }

        @Override
        public int characteristics() { return characteristics; }

        @Override
        public Comparator getComparator() {
            if (hasCharacteristics(Spliterator.SORTED))
            	//如果是sorted,返回null,否则抛出IllegalStateException
                return null;
            throw new IllegalStateException();
        }
    }

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(java容器,源码分析)