集合源码学习(二):Spliterator

何为Spliterator?

Java8新增加了Spliterator类,和以前的Iterator迭代器相比,Spliterator又被称为分割迭代器,即可以支持不同位置访问方式迭代,即并行的方式进行迭代。
先看注解后的代码:

public interface Spliterator<T> {
    /**
     * 执行一个元素的操作,也就是action里面的操作,如果有元素则返回true
     * 没有元素返回false。
     */
    boolean tryAdvance(Consumer<? super T> action);

    /**
     * 以此执行所有元素的action里面动作
     */
    default void forEachRemaining(Consumer<? super T> action) {
        do { } while (tryAdvance(action));
    }

    /**
     * 如果这个(集合)能够被分割,返回一个分割迭代器
     * @return
     */
    Spliterator<T> trySplit();

    /**
     * 返回元素的估计数量,可以用forEachRemaining来获得,
     * 如果由于元素太多或者并不知道数量
     * 返回Long里面的MAX_VALUE
     */
    long estimateSize();

    /**
     * 如果知道就返回准确数字,否则返回-1.
     */
    default long getExactSizeIfKnown() {
        return (characteristics() & SIZED) == 0 ? -1L : estimateSize();
    }

    /**
     * 返回对象具有哪些特征值:
     * 例如有以下可选:
     * 表明元素有哪些特征
     * #ORDERED 
     * #DISTINCT 
     * #SORTED 
     * #SIZED
     * #NONNULL 
     * #IMMUTABLE
     * #CONCURRENT
     * #SUBSIZED
     */
    int characteristics();

    /**
     * 如果分割迭代器包括所给的所有特征,则返回true
     * 具体实现的方法
     */
    default boolean hasCharacteristics(int characteristics) {
        return (characteristics() & characteristics) == characteristics;
    }

    /**
     * 如果这个分割迭代器的元素是通过Comparator排好序的SORTED元素,就返回Comparator,
     * 如果元素不是SORTED的,则抛出错误。
     */
    default Comparator<? super T> getComparator() {
        throw new IllegalStateException();
    }

    //众多特征值
    public static final int ORDERED    = 0x00000010;
    public static final int DISTINCT   = 0x00000001;
    public static final int SORTED     = 0x00000004;
    public static final int SIZED      = 0x00000040;
    public static final int NONNULL    = 0x00000100;
    public static final int IMMUTABLE  = 0x00000400;
    public static final int CONCURRENT = 0x00001000;
    public static final int SUBSIZED = 0x00004000;
}

相关特征值具体意思

类型描述
CONCURRENT特征值表示可以通过多个线程安全同时修改元素源(允许添加,替换和/或删除),而无需外部同步。
DISTINCT特征值表示,对于每对遇到的元素x, y,!x.equals(y)
IMMUTABLE特征值表示元素源不能在结构上进行修改; 也就是说,不能添加,替换或删除元素,因此在遍历过程中不会发生这种更改。
NONNULL特征值表示源保证遇到的元素不会null。
ORDERED特征值表示为元素定义遇到顺序。
SIZED特征值表示从estimateSize()遍历或分割之前返回的值 表示有限大小,在没有结构源修改的情况下,表示完全遍历将遇到的元素数量的精确计数。
SORTED特征值表示遇到的顺序遵循定义的排序顺序。
SUBSIZED特征值表示由所产生的所有Spliterator trySplit()都将SIZED和SUBSIZED。

衍生的接口
另外,在Spliterator源码里面还有一些衍生的接口:OfInt, OfDouble, OfLong以及OfPrimitive ,从代码里面可以看出来,结构大部分和Spliterator相同,这里介绍OfPrimitive

    public interface OfPrimitive<T, T_CONS, T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>>
            extends Spliterator<T> {
        @Override
        T_SPLITR trySplit();


        @SuppressWarnings("overloads")
        boolean tryAdvance(T_CONS action);

        @SuppressWarnings("overloads")
        default void forEachRemaining(T_CONS action) {
            do { } while (tryAdvance(action));
        }
    }

由上代码可知,OfPrimitive 只是在原接口基础上,又增加了两个泛型,用于限定tryAdvanceforEachRemaining的参数。相当于规范化了一遍。

ArrayList里面用到的Spliterator

先看我注释过的源码:

    static final class ArrayListSpliterator<E> implements Spliterator<E> {

        private final ArrayList<E> list;        //传入的ArrayList
        private int index;                     // 当前位置
        private int fence;                      // 末尾位置
        private int expectedModCount;           // modcount,即同时修改的线程数。

        /** 在给定的集合范围内创建一个Spliterator */
        ArrayListSpliterator(ArrayList<E> list, int origin, int fence,
                             int expectedModCount) {
            this.list = list; // OK if null unless traversed
            this.index = origin;
            this.fence = fence;
            this.expectedModCount = expectedModCount;
        }

        /**
         * 获取末尾位置
         * @return
         */
        private int getFence() { 
            int hi; 
            ArrayList<E> lst;
            if ((hi = fence) < 0) {   //也可以理解为初始化
                if ((lst = list) == null)
                    hi = fence = 0;
                else {
                    expectedModCount = lst.modCount;
                    hi = fence = lst.size;
                }
            }
            return hi;
        }

        public ArrayListSpliterator<E> trySplit() {
            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
            return (lo >= mid) ? null : //如果可以分割则进行分割返回一个迭代器
                new ArrayListSpliterator<E>(list, lo, index = mid,
                                            expectedModCount);  //返回分割前半段一个Spliterator
        }

        /**
         * 执行一个action,并使index+1
         * @param action
         * @return
         */
        public boolean tryAdvance(Consumer<? super E> action) {
            if (action == null)
                throw new NullPointerException();
            int hi = getFence(), i = index;
            if (i < hi) {
                index = i + 1;
                @SuppressWarnings("unchecked") E e = (E)list.elementData[i];
                action.accept(e);
                //访问线程多余允许线程,则会抛出异常
                if (list.modCount != expectedModCount)
                    throw new ConcurrentModificationException();
                return true;
            }
            return false;
        }
        /**
         * 遍历本Spliterator下面所有元素,并执行action。
         * 注意是本Spliterator
         * 多余一个线程会报错
         */
        public void forEachRemaining(Consumer<? super E> action) {
            int i, hi, mc; // hoist accesses and checks from loop
            ArrayList<E> lst; Object[] a;
            if (action == null)
                throw new NullPointerException();
            if ((lst = list) != null && (a = lst.elementData) != null) {
                if ((hi = fence) < 0) {
                    mc = lst.modCount;
                    hi = lst.size;
                }
                else
                    mc = expectedModCount;
                if ((i = index) >= 0 && (index = hi) <= a.length) {
                    for (; i < hi; ++i) {
                        @SuppressWarnings("unchecked") E e = (E) a[i];
                        action.accept(e);
                    }
                    if (lst.modCount == mc)
                        return;
                }
            }
            throw new ConcurrentModificationException();
        }
        /**
         * 在ArrayList中,估计大小是确定的,但这仅仅是本Spliterator里面的
         * @return
         */
        public long estimateSize() {
            return (long) (getFence() - index);
        }
        /**
         * 说明在ArrayList中,它的Spliterator具有哪些特征。
         * 顺序性,
         * 可确定范围
         * 分割下去的子Spliterator也是可却定范围的。
         * @return
         */
        public int characteristics() {
            return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
        }
    }

当然如果自己想写过一个类,也可以模仿ArrayListSpliterator写一个Spliterator实现类,定义自己的特征

接下来看ArrayList结合ArrayListIterator的简单应用:

    public static void main(String[] args) {
        List<Character> arrs = new ArrayList<Character>();
        for (int i = 97; i < 122; i++) {
            arrs.add((char) i);
        }

        // 此时结果:spliterator1:index=0,fence=-1
                //由源码可知,-1也就是代表集合长度,即25
        Spliterator<Character> spliterator1 = arrs.spliterator();

        // 此时结果:spliterator2:index=0,fence=12
        //         spliterator1:index=12,fence=25,
        Spliterator<Character> spliterator2 = spliterator1.trySplit();

        // 此时结果:spliterator3:index=12,fence=18
        // 而       spliterator1:index=18,fence=25
        Spliterator<Character> spliterator3 = spliterator1.trySplit();

        // 此时结果:spliterator4:index=18,fence=21,
        //         spliterator1:index=21,fence=25,
        Spliterator<Character> spliterator4 = spliterator1.trySplit();

    }

至此,Spliterator,正如命名一样,就是一个可分割的迭代器,以前传统的Iterator能够迭代整个集合,但是不能迭代一部分,而Spliterator则可以迭代集合的一部分,同时,自己实现时,可以让其支持并行而不加锁的迭代一个集合。而Spliterator的特征值,仅仅是表示特征而已,程序员自己实现的Spliterator,里面包含什么特征就写什么特征。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值