java基础-Steam[3]-Spliterator接口

Spliterator接口

Spliterator(splitable iterator可分割迭代器)接口是Java为了并行遍历数据源中的元素而设计的迭代器,这个可以类比最早Java提供的顺序遍历迭代器Iterator,但一个是顺序遍历,一个是并行遍历。

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));
    }
    // 将原来 spliterator 进行分区,生成新的spliterator
    //firstSpliterator 包含[1,2,3,4,5],
    //secSpliterator = spliterator.trySplit()则可能返回包含[3,4,5]的spliterator
    //而firstSpliterator只保留[1,2]
    //这可以将原spliterator拆分为多个部分,以便并行同步处理
    //Spliterator如果包含无穷个元素,则trySplit()返回null
    Spliterator<T> trySplit();

    //返回将遇到的元素数量的估计值,如果无限,未知或计算成本太高,则返回Long.MAX_VALUE。
    //如果此Spliterator为SIZED且尚未部分遍历或拆分,或者此Spliterator已进行SUBSIZED且尚未部分遍历,则此估计值必须是完整遍历将遇到的元素的准确计数。否则,此估计值可能是任意不准确的,但必须按照trySplit()调用中指定的方式减少。
    long estimateSize();

    //Convenience method that returns {@link #estimateSize()} if this Spliterator is {@link #SIZED}, else {@code -1}.
    default long getExactSizeIfKnown() {
        return (characteristics() & SIZED) == 0 ? -1L : estimateSize();
    }

    // 返回该Spliterator的特征值集合,ORDERED、DISTINCT、SORTED、SIZED、NONNULL、IMMUTABLE、CONCURRENT、SUBSIZED
    // 在trySplit调用之前或之间对给定spliterator上的characteristics()重复调用应始终返回相同的结果。
    int characteristics();

    //如果此Spliterator的characteristics()包含所有给定特性,则返回true,否则为false。
    default boolean hasCharacteristics(int characteristics) {
        return (characteristics() & characteristics) == characteristics;
    }

    // 如果此Spliterator的源由Comparator比较器为SORTED,则返回该Comparator。如果源按Comparable自然顺序为SORTED,则返回null。否则,如果源不是SORTED,则抛出IllegalStateException。
    default Comparator<? super T> getComparator() {
        throw new IllegalStateException();
    }
}

Spliterator示例

public static void main(String[] args) {
    Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9);
    Spliterator<Integer> firstSpliterator = stream.spliterator();
    Spliterator<Integer> secondSpliterator = firstSpliterator.trySplit();
    Spliterator<Integer> thirdSpliterator = firstSpliterator.trySplit();
    System.out.println("firstSpliterator");
    while (firstSpliterator.tryAdvance(n -> System.out.println("first =>" + n))) {

    }
    System.out.println("secondSpliterator");
    while (secondSpliterator.tryAdvance(n -> System.out.println("second =>" + n))) {

    }
    System.out.println("thirdSpliterator");
    while (thirdSpliterator.tryAdvance(n -> System.out.println("third =>" + n))) {

    }
}
firstSpliterator
first =>7
first =>8
first =>9
secondSpliterator
second =>1
second =>2
second =>3
second =>4
thirdSpliterator
third =>5
third =>6

ArrayList

public Spliterator<E> spliterator() {
	return new ArrayListSpliterator(0, -1, 0);
}

final class ArrayListSpliterator implements Spliterator<E> {


    private int index; // current index, modified on advance/split
    private int fence; // -1 until used; then one past last index
    private int expectedModCount; // initialized when fence set

    /** Creates new spliterator covering the given range. */
    ArrayListSpliterator(int origin, int fence, int expectedModCount) {
        this.index = origin;
        this.fence = fence;
        this.expectedModCount = expectedModCount;
    }

    private int getFence() { // initialize fence to size on first use
        int hi; // (a specialized variant appears in method forEach)
        if ((hi = fence) < 0) {
            expectedModCount = modCount;
            hi = fence = size;
        }
        return hi;
    }

    public ArrayListSpliterator trySplit() {
        int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
        return (lo >= mid) ? null : // divide range in half unless too small
        new ArrayListSpliterator(lo, index = mid, expectedModCount);
    }

    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)elementData[i];
            action.accept(e);
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            return true;
        }
        return false;
    }
    //根据索引访问遍历数组,在最后终止操作时会调用该方法
    public void forEachRemaining(Consumer<? super E> action) {
        int i, hi, mc; // hoist accesses and checks from loop
        Object[] a;
        if (action == null)
            throw new NullPointerException();
        if ((a = elementData) != null) {
            if ((hi = fence) < 0) {
                mc = modCount;
                hi = 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 (modCount == mc)
                    return;
            }
        }
        throw new ConcurrentModificationException();
    }

    public long estimateSize() {
        return getFence() - index;
    }

    public int characteristics() {
        return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
    }
}

参考

  1. Java8中Spliterator详解
posted @ 2021-04-19 11:04  froggengo  阅读(239)  评论(0编辑  收藏  举报