-
- 参数类型
-
T
- 此Spliterator返回的元素类型
- All Known Subinterfaces:
-
Spliterator.OfDouble
,Spliterator.OfInt
,Spliterator.OfLong
,Spliterator.OfPrimitive<T,T_CONS,T_SPLITR>
- 所有已知实现类:
-
Spliterators.AbstractDoubleSpliterator
,Spliterators.AbstractIntSpliterator
,Spliterators.AbstractLongSpliterator
,Spliterators.AbstractSpliterator
public interface Spliterator<T>
用于遍历和分区源元素的对象。 Spliterator覆盖的元素源可以是例如阵列,Collection
,IO通道或生成器函数。Spliterator可以单独遍历元素(
tryAdvance()
)或按顺序遍历元素(forEachRemaining()
)。Spliterator还可以将其某些元素(使用
trySplit()
)作为另一个Spliterator进行分区,以用于可能并行的操作。 使用无法拆分的Spliterator或以高度不平衡或低效的方式进行操作的操作不太可能从并行性中受益。 横向和分离排气元件; 每个Spliterator仅对单个批量计算有用。甲Spliterator还报告一组
characteristics()
选自其结构,源极和元件的ORDERED
,DISTINCT
,SORTED
,SIZED
,NONNULL
,IMMUTABLE
,CONCURRENT
,和SUBSIZED
。 Spliterator客户端可以使用这些来控制,专门化或简化计算。 例如,Collection
的Spliterator将报告SIZED
的Spliterator将报告DISTINCT
,而SortedSet
的Spliterator也报告SORTED
。 特征报告为简单的联合位集。 一些特征还限制了方法行为; 例如,如果ORDERED
,遍历方法必须符合其记录的顺序。 未来可能会定义新特征,因此实现者不应将意义分配给未列出的值。A Spliterator that does not report
IMMUTABLE
orCONCURRENT
is expected to have a documented policy concerning: when the spliterator binds to the element source; and detection of structural interference of the element source detected after binding. 后期绑定 Spliterator在第一次遍历,第一次拆分或第一次查询估计大小时绑定到元素源,而不是在创建Spliterator时绑定。 非后期绑定的 Spliterator在构造点或任何方法的第一次调用时绑定到元素源。 遍历Spliterator时会反映在绑定之前对源进行的修改。 绑定Spliterator后,如果检测到结构性干扰, 应尽最大努力抛出ConcurrentModificationException
。 执行此操作的Spliterators称为快速失败 。 Spliterator的批量遍历方法(forEachRemaining()
)可以优化遍历并在遍历所有元素之后检查结构干扰,而不是检查每个元素并立即失败。Spliterators可以通过
estimateSize()
方法估算剩余元素的数量。 理想情况下,如特征SIZED
中所反映的,该值与成功遍历中遇到的元素数量完全对应。 然而,即使不完全已知,估计值对于在源上执行的操作仍然是有用的,例如帮助确定是否优选地进一步分割或顺序遍历剩余元素。尽管它们在并行算法中具有明显的实用性,但预计分裂器不是线程安全的。 相反,使用分裂器的并行算法的实现应确保分裂器一次仅由一个线程使用。 这通常很容易通过串行线程限制来实现,这通常是通过递归分解工作的典型并行算法的自然结果。 调用
trySplit()
的线程可以将返回的Spliterator移交给另一个线程,该线程又可以遍历或进一步拆分该Spliterator。 如果两个或多个线程在同一个spliterator上同时运行,则拆分和遍历的行为是不确定的。 如果原始线程将分离器移交给另一个线程进行处理,最好是在使用tryAdvance()
消耗任何元素之前进行切换,因为某些保证(例如4510720863823对于SIZED
分裂器的准确性)仅在遍历开始之前有效。的原始亚型特
Spliterator
被提供用于int
,long
,和double
值。 子类型默认实现tryAdvance(java.util.function.Consumer)
和forEachRemaining(java.util.function.Consumer)
框原始值到其对应的包装类的实例。 这种装箱可能会破坏使用原始专业化所获得的任何性能优势。 为避免装箱,应使用相应的基于图元的方法。 例如,Spliterator.OfPrimitive.tryAdvance(java.util.function.IntConsumer)
和Spliterator.OfPrimitive.forEachRemaining(java.util.function.IntConsumer)
应优先用于Spliterator.OfInt.tryAdvance(java.util.function.Consumer)
和Spliterator.OfInt.forEachRemaining(java.util.function.Consumer)
。 使用基于装箱的方法tryAdvance()
和forEachRemaining()
遍历原始值不会影响遇到转换为盒装值的值的顺序。- API Note:
-
Spliterators,如
Iterator
,用于遍历源的元素。 除了顺序遍历之外,Spliterator
API还支持有效的并行遍历,支持分解以及单元素迭代。 此外,通过Spliterator访问元素的协议旨在施加比Iterator
更小的每元素开销,并避免与hasNext()
和next()
具有单独方法相关的固有竞争。对于可变源,如果源在Spliterator绑定到其数据源的时间与遍历结束之间受到结构干扰(元素添加,替换或删除),则可能会发生任意和非确定性行为。 例如,当使用
java.util.stream
框架时,此类干扰将产生任意的,不确定的结果。源的结构干扰可以通过以下方式进行管理(大致降低合意性的顺序):
- 源不能在结构上受到干扰。
例如,CopyOnWriteArrayList
的实例是不可变的源。 从源创建的IMMUTABLE
报告IMMUTABLE
的特征。 - 源管理并发修改。
例如,ConcurrentHashMap
的密钥集是并发源。 从源创建的CONCURRENT
报告特征为CONCURRENT
。 - 可变源提供了后期绑定和失败快速的Spliterator。
后期绑定使窗口变窄,在此期间干扰会影响计算; 在遍历开始并且抛出ConcurrentModificationException
之后,在尽力而为的基础上快速检测到结构干扰已经发生。 例如, JDK中的ArrayList
和许多其他非并发Collection
类提供了一种后期绑定,失败快速的分裂器。 - 可变源提供非后期绑定但失败快速的Spliterator。
由于潜在干扰窗口较大,因此增加投掷ConcurrentModificationException
的可能性。 - 可变源提供了后期绑定和非故障快速Spliterator。
由于未检测到干扰,在遍历开始之后,源会冒任意,非确定性行为。 - 可变源提供非后期绑定和非故障快速Spliterator。
源增加了任意,非确定性行为的风险,因为在构造之后可能发生未检测到的干扰。
例。 这是一个类(不是非常有用的,除了插图),它维护一个数组,其中实际数据保存在偶数位置,而不相关的标签数据保存在奇数位置。 它的Spliterator忽略标签。
class TaggedArray<T> { private final Object[] elements; // immutable after construction TaggedArray(T[] data, Object[] tags) { int size = data.length; if (tags.length != size) throw new IllegalArgumentException(); this.elements = new Object[2 * size]; for (int i = 0, j = 0; i < size; ++i) { elements[j++] = data[i]; elements[j++] = tags[i]; } } public Spliterator<T> spliterator() { return new TaggedArraySpliterator<>(elements, 0, elements.length); } static class TaggedArraySpliterator<T> implements Spliterator<T> { private final Object[] array; private int origin; // current index, advanced on split or traversal private final int fence; // one past the greatest index TaggedArraySpliterator(Object[] array, int origin, int fence) { this.array = array; this.origin = origin; this.fence = fence; } public void forEachRemaining(Consumer<? super T> action) { for (; origin < fence; origin += 2) action.accept((T) array[origin]); } public boolean tryAdvance(Consumer<? super T> action) { if (origin < fence) { action.accept((T) array[origin]); origin += 2; return true; } else // cannot advance return false; } public Spliterator<T> trySplit() { int lo = origin; // divide range in half int mid = ((lo + fence) >>> 1) & ~1; // force midpoint to be even if (lo < mid) { // split out left half origin = mid; // reset this Spliterator's origin return new TaggedArraySpliterator<>(array, lo, mid); } else // too small to split return null; } public long estimateSize() { return (long)((fence - origin) / 2); } public int characteristics() { return ORDERED | SIZED | IMMUTABLE | SUBSIZED; } } }
作为一个例子,并行计算框架(如
java.util.stream
包)将如何在并行计算中使用Spliterator,这是实现关联并行forEach的一种方法,它说明了在估计工作量之前拆分子任务的主要用法习惯用法小到足以按顺序执行。 这里我们假设跨子任务的处理顺序无关紧要; 不同(分叉)任务可以以不确定的顺序进一步分割和处理元素。 这个例子使用了CountedCompleter
; 类似的用法适用于其他并行任务结构。static <T> void parEach(TaggedArray<T> a, Consumer<T> action) { Spliterator<T> s = a.spliterator(); long targetBatchSize = s.estimateSize() / (ForkJoinPool.getCommonPoolParallelism() * 8); new ParEach(null, s, action, targetBatchSize).invoke(); } static class ParEach<T> extends CountedCompleter<Void> { final Spliterator<T> spliterator; final Consumer<T> action; final long targetBatchSize; ParEach(ParEach<T> parent, Spliterator<T> spliterator, Consumer<T> action, long targetBatchSize) { super(parent); this.spliterator = spliterator; this.action = action; this.targetBatchSize = targetBatchSize; } public void compute() { Spliterator<T> sub; while (spliterator.estimateSize() > targetBatchSize && (sub = spliterator.trySplit()) != null) { addToPendingCount(1); new ParEach<>(this, sub, action, targetBatchSize).fork(); } spliterator.forEachRemaining(action); propagateCompletion(); } }
- 源不能在结构上受到干扰。
- Implementation Note:
-
如果布尔系统属性
org.openjdk.java.util.stream.tripwire
设置为true
则在对原始子类型特化进行操作时,如果出现原始值的装箱,则会报告诊断警告。 - 从以下版本开始:
- 1.8
- 另请参见:
-
Collection
-
-
嵌套类汇总
嵌套类 变量和类型 接口 描述 static interface
Spliterator.OfDouble
Spliterator专门用于double
值。static interface
Spliterator.OfInt
Spliterator专门用于int
值。static interface
Spliterator.OfLong
Spliterator专门用于long
值。static interface
Spliterator.OfPrimitive<T,T_CONS,T_SPLITR extends Spliterator.OfPrimitive<T,T_CONS,T_SPLITR>>
专门用于原始值的Spliterator。
-
字段汇总
字段 变量和类型 字段 描述 static int
CONCURRENT
表示可以在没有外部同步的情况下由多个线程安全地同时修改元素源(允许添加,替换和/或删除)的特征值。static int
DISTINCT
特性值这标志着,对于每对遇到的元件的x, y
,!x.equals(y)
。static int
IMMUTABLE
表示元素源不能进行结构修改的特征值; 也就是说,无法添加,替换或删除元素,因此在遍历期间不会发生此类更改。static int
NONNULL
特征值表示源保证遇到的元素不会是null
。static int
ORDERED
表示为元素定义遭遇顺序的特征值。static int
SIZED
表示在遍历或拆分之前从estimateSize()
返回的值的特征值表示有限大小,在没有结构源修改的情况下,表示完整遍历将遇到的元素数量的精确计数。static int
SORTED
表示遇到订单遵循已定义排序顺序的特征值。static int
SUBSIZED
-
方法摘要
所有方法 实例方法 抽象方法 Default Methods 变量和类型 方法 描述 int
characteristics()
返回此Spliterator及其元素的一组特征。long
estimateSize()
返回forEachRemaining(java.util.function.Consumer<? super T>)
遍历将遇到的元素数量的估计值,如果无限,未知或计算成本太高,则返回Long.MAX_VALUE
。default void
forEachRemaining(Consumer<? super T> action)
在当前线程中按顺序对每个剩余元素执行给定操作,直到所有元素都已处理或操作引发异常。default Comparator<? super T>
getComparator()
如果此Spliterator的源为4510721246171 , 则为Comparator
,则返回Comparator
。default long
getExactSizeIfKnown()
default boolean
hasCharacteristics(int characteristics)
如果此Spliterator的characteristics()
包含所有给定特征,则返回true
。boolean
tryAdvance(Consumer<? super T> action)
如果存在剩余元素,则对其执行给定操作,返回true
; 否则返回false
。Spliterator<T>
trySplit()
如果可以对此spliterator进行分区,则返回Spliterator覆盖元素,这些元素在从此方法返回时将不被此Spliterator覆盖。
-
-
-
字段详细信息
-
ORDERED
static final int ORDERED
表示为元素定义遭遇顺序的特征值。 如果是,则此Spliterator保证方法trySplit()
拆分严格的元素前缀,方法tryAdvance(java.util.function.Consumer<? super T>)
按前缀顺序逐个元素,并且forEachRemaining(java.util.function.Consumer<? super T>)
按遭遇顺序执行操作。如果相应的
Collection.iterator()
记录订单,则Collection
具有遭遇订单。 如果是,则遭遇订单与记录的订单相同。 否则,集合没有遭遇订单。
-
DISTINCT
static final int DISTINCT
特性值这标志着,对于每对遇到的元件的x, y
,!x.equals(y)
。 例如,这适用于基于Set
的Spliterator 。- 另请参见:
- 常数字段值
-
SORTED
static final int SORTED
表示遇到订单遵循已定义排序顺序的特征值。 如果是这样,方法getComparator()
返回关联比较,或null
如果所有元素都是Comparable
,并通过其自然顺序进行排序。报告
SORTED
还必须报告ORDERED
。- API Note:
-
JDK中
Collection
类的分裂器实现NavigableSet
或SortedSet
报告SORTED
。 - 另请参见:
- 常数字段值
-
SIZED
static final int SIZED
表示在遍历或拆分之前从estimateSize()
返回的值的特征值表示有限大小,在没有结构源修改的情况下,表示完整遍历将遇到的元素数量的精确计数。
-
NONNULL
static final int NONNULL
表示源保证遇到的元素不是null
特征值。 (例如,这适用于大多数并发集合,队列和映射。)- 另请参见:
- 常数字段值
-
IMMUTABLE
static final int IMMUTABLE
表示元素源不能进行结构修改的特征值; 也就是说,无法添加,替换或删除元素,因此在遍历期间不会发生此类更改。 未报告IMMUTABLE
或CONCURRENT
应具有关于遍历期间检测到的结构干扰的文档化策略(例如,抛出ConcurrentModificationException
)。- 另请参见:
- 常数字段值
-
CONCURRENT
static final int CONCURRENT
表示可以在没有外部同步的情况下由多个线程安全地同时修改元素源(允许添加,替换和/或删除)的特征值。 如果是这样,Spliterator应该有一个关于遍历期间修改影响的书面政策。顶级Spliterator不应报告
CONCURRENT
和SIZED
,因为如果已知,有限大小可能会在遍历期间同时修改源时发生更改。 这样的Spliterator是不一致的,并且不能保证使用该Spliterator进行任何计算。 如果已知子分割尺寸,则子分割器可以报告SIZED
,并且在遍历时不反映对源的添加或移除。顶级Spliterator不应报告
CONCURRENT
和IMMUTABLE
,因为它们是互斥的。 这样的Spliterator是不一致的,并且不能保证使用该Spliterator进行任何计算。 如果在遍历时未反映对源的添加或删除,则子分类符可以报告IMMUTABLE
。- API Note:
- 大多数并发收集保持一致性策略,保证Spliterator构造点处存在的元素的准确性,但可能不反映后续添加或删除。
- 另请参见:
- 常数字段值
-
-
方法详细信息
-
tryAdvance
boolean tryAdvance(Consumer<? super T> action)
- 参数
-
action
- 动作 - 结果
-
false
如果在进入此方法时没有剩余元素,true
。 - 异常
-
NullPointerException
- 如果指定的操作为null
-
forEachRemaining
default void forEachRemaining(Consumer<? super T> action)
- 实现要求:
-
默认实现重复调用
tryAdvance(java.util.function.Consumer<? super T>)
,直到它返回false
。 应该尽可能地覆盖它。 - 参数
-
action
- 动作 - 异常
-
NullPointerException
- 如果指定的操作为null
-
trySplit
Spliterator<T> trySplit()
如果可以对此spliterator进行分区,则返回Spliterator覆盖元素,这些元素在从此方法返回时将不被此Spliterator覆盖。如果此Spliterator为
ORDERED
,则返回的Spliterator必须覆盖元素的严格前缀。除非此Spliterator包含无限数量的元素,否则重复调用
trySplit()
最终必须返回null
。 在非null返回时:- 在拆分之前为
estimateSize()
报告的值,在拆分后,必须大于或等于estimateSize()
和返回的Spliterator; 和 - 如果此Spliterator为
SUBSIZED
,则estimateSize()
前的此拆分器的estimateSize()必须等estimateSize()
为estimateSize()
和拆分后返回的Spliterator之和。
由于任何原因,该方法可能返回
null
,包括null
,在遍历开始后无法拆分,数据结构约束和效率考虑。- API Note:
-
理想的
trySplit
方法(无遍历)将其元素精确地分成两半,从而实现平衡并行计算。 许多偏离这种理想仍然非常有效; 例如,仅大致分割近似平衡的树,或者叶子节点可能包含一个或两个元素的树,无法进一步分割这些节点。 然而,平衡性和/或效率trySplit
大偏差通常导致差的并行性能。 - 结果
-
一个
Spliterator
覆盖所述元件的一些部分,或者null
如果此spliterator不能拆分
- 在拆分之前为
-
estimateSize
long estimateSize()
返回forEachRemaining(java.util.function.Consumer<? super T>)
遍历将遇到的元素数量的估计值,如果无限,未知或计算成本太高,则返回Long.MAX_VALUE
。如果此Spliterator为
SIZED
且尚未部分遍历或拆分,或者此Spliterator为SUBSIZED
且尚未部分遍历,则此估计值必须是完整遍历将遇到的元素的准确计数。 否则,此估计可能是任意不准确的,但必须按照trySplit()
的调用指定的方式减少 。- API Note:
- 即使是不精确的估计通常也很有用且计算成本低廉。 例如,近似平衡的二叉树的子分裂器可以返回一个值,该值估计元素的数量是其父元素的一半; 如果根Spliterator没有保持准确的计数,它可以估计大小为对应于其最大深度的2的幂。
- 结果
-
估计大小,或
Long.MAX_VALUE
如果计算无限,未知或太昂贵。
-
getExactSizeIfKnown
default long getExactSizeIfKnown()
- 实现要求:
-
如果Spliterator报告特征为
SIZED
,则默认实现返回estimateSize()
的结果,estimateSize()
返回-1
。 - 结果
-
确切的大小,如果知道,否则
-1
。
-
characteristics
int characteristics()
返回此Spliterator及其元素的一组特征。 结果从表示为或运算值ORDERED
,DISTINCT
,SORTED
,SIZED
,NONNULL
,IMMUTABLE
,CONCURRENT
,SUBSIZED
。 反复拨打characteristics()
在给定的spliterator之前或在两者之间的调用,trySplit
,应始终返回相同的结果。如果Spliterator报告一组不一致的特征(从单个调用或多个调用返回的特征),则无法保证使用此Spliterator进行任何计算。
- API Note:
-
分裂前给定分裂器的特性可能与分裂后的特征不同。
对于具体的例子看到的特性值
SIZED
,SUBSIZED
和CONCURRENT
。 - 结果
- 表征特征
-
hasCharacteristics
default boolean hasCharacteristics(int characteristics)
如果此Spliterator的characteristics()
包含所有给定特征,则返回true
。- 实现要求:
- 如果设置了给定特征的相应位,则默认实现返回true。
- 参数
-
characteristics
- 要检查的特征 - 结果
-
true
如果存在所有指定的特征,false
-
getComparator
default Comparator<? super T> getComparator()
如果此Spliterator的源为SORTED
, 则为Comparator
,则返回Comparator
。 如果源是SORTED
,请访问natural order ,返回null
。 否则,如果源不是SORTED
,则抛出IllegalStateException
。- 实现要求:
-
默认实现始终抛出
IllegalStateException
。 - 结果
-
如果元素按自然顺序排序,
null
比较器或null
。 - 异常
-
IllegalStateException
- 如果分裂器未报告SORTED
的特征。
-
-