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;
}
}