1. 程式人生 > 實用技巧 >探索ArrayListSpliterator底層實現

探索ArrayListSpliterator底層實現

前言

上次看ArrayList底層機制時把ArrayListSpliterator放了放,現在回過頭來具體看看實現。

簡單粗暴

直接上程式碼吧!


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

        //指向當前集合物件
        private final ArrayList<E> list;

        //當前索引,可能被trySplit和tryAdvance操作修改
        private int index;

        //結束索引,未使用前為-1,使用後為list的size
        private int fence;

        //通過與modCount比較來判斷集合是否被修改,初始值與modCount相等
        private int expectedModCount;

        /**
         * 初始化引數
         * @param list 當前集合
         * @param origin 起始索引
         * @param fence 結束索引
         * @param expectedModCount 
         */
        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;
        }

        /**
         * 獲取結束索引
         * 初始化expectedModCount與fence引數
         * @return 結束索引
         */
        private int getFence() { // initialize fence to size on first use
            int hi; // (a specialized variant appears in method forEach)
            ArrayList<E> lst;
            if ((hi = fence) < 0) {
                if ((lst = list) == null)
                    hi = fence = 0;
                else {
                    expectedModCount = lst.modCount;
                    hi = fence = lst.size;
                }
            }
            return hi;
        }

        /**
         * 在當前切割迭代器的基礎上再次拆分一個新的迭代器
         * 若切割迭代器是可以拆分的,會返回新的一個切割迭代器,兩個迭代器平分原先迭代器中的元素
         * 若切割迭代器無法拆分的話,則返回null
         * 拆分後原先迭代器必須修改起始索引,因為它的元素被拆分了(index = mid)
         * @return 新的切割迭代器或null
         */
        public ArrayListSpliterator<E> trySplit() {
            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
            return (lo >= mid) ? null : // divide range in half unless too small
                new ArrayListSpliterator<E>(list, lo, index = mid,
                                            expectedModCount);
        }

        /**
         * 若存在剩餘元素,則對其下一個元素執行指定動作,並返回true
         * 若不存在剩餘元素,則返回false
         * 該方法是對單獨元素進行操作
         * @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;
        }

        /**
         * 遍歷剩餘元素,並執行指定動作
         * @param action 若存在剩餘元素,執行指定動作
         */
        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();
        }

        /**
         * 獲取切割迭代器的元素個數
         * 計算結束索引與起始索引之間的元素個數
         * @return 切割迭代器的元素個數 
         */
        public long estimateSize() {
            return (long) (getFence() - index);
        }

        /**
         * 獲取切割迭代器的特徵值
         * ArrayList底層實現是陣列,故是有序、有實際大小、可重複、可存入null、屬於非執行緒安全、在遍歷時可新增修改替換元素
         */
        public int characteristics() {
            return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
        }

    }

總結

  • 分割迭代器可以單個(tryAdvance)或順序(多個)遍歷元素。

  • 分割迭代器可拆分成若干個小型的分割迭代器來並行操作元素。

  • 分割迭代器屬於非執行緒安全。

  • ArrayListSpliterator屬於後期繫結與快速失敗的分割迭代器。