集合源码学习(二):Spliterator

来源:互联网 发布:a5源码被骗 编辑:程序博客网 时间:2024/05/17 08:48

何为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,里面包含什么特征就写什么特征。

原创粉丝点击