Module  java.base
软件包  java.util

Interface Spliterator<T>

  • 参数类型
    T - 此Spliter的返回元素的类型
    All Known Subinterfaces:
    Spliterator.OfDoubleSpliterator.OfIntSpliterator.OfLongSpliterator.OfPrimitive<T,T_CONS,T_SPLITR>
    所有已知实现类:
    Spliterators.AbstractDoubleSpliteratorSpliterators.AbstractIntSpliteratorSpliterators.AbstractLongSpliteratorSpliterators.AbstractSpliterator


    public interface Spliterator<T>
    用于遍历和分割源的元素的对象。 Spliterator覆盖的元素的来源可以是例如阵列, Collection ,IO通道或生成器函数。

    分割器可以逐个遍历元素( tryAdvance() )或批量( forEachRemaining() )。

    分割器还可以将其一些元素(使用trySplit()分割为另一个分割器,以在可能的并行操作中使用。 使用不能分割的Spliter的操作或者以非常不平衡或低效的方式进行的操作不太可能受益于并行性。 穿透和分流排气元件; 每个Spliterator仅对单个批量计算有用。

    甲Spliterator还报告一组characteristics()选自其结构,源极和元件的ORDEREDDISTINCTSORTEDSIZEDNONNULLIMMUTABLECONCURRENT ,和SUBSIZED 这些可以由Spliterator客户端使用来控制,专门化或简化计算。 例如,CollectionSpliterator将报告SIZEDSpliterator将报告DISTINCT ,并且SortedSetSpliterator也将报告SORTED 特性报告为简单的单位位。 一些特征还限制了方法行为; 例如,如果ORDERED ,遍历方法必须符合其记录的顺序。 未来可能会定义新特性,因此实现者不应将含义分配给未列出的值。

    A Spliterator that does not report IMMUTABLE or CONCURRENT 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在首次遍历,第一次拆分或第一个查询时针对估计大小而不是在创建Spliter时绑定到元素的来源。 没有晚期绑定的拼接器在构造或首次调用任何方法时绑定到元素的来源。 在绑定之前对源进行的修改在Spliter运行时被反映。 绑定后,如果检测到结构性干扰,尽力而为,应该抛出ConcurrentModificationException 这样做的分割器称为故障快速 分割器的批量遍历方法( forEachRemaining() )可以优化遍历并检查所有元素已经遍历之后的结构干扰,而不是立即检查每个元素并失败。

    分配器可以通过estimateSize()方法提供剩余元素数量的估计。 理想情况下,如特征SIZED所反映的,该值与在成功遍历中遇到的元素的数量完全对应。 然而,即使不完全知道,估计值对于在源上执行的操作仍然可能是有用的,例如有助于确定是否优选进一步分割或者顺序地遍历剩余的元素。

    尽管它们在并行算法中具有明显的实用性,但拼接器并不期望是线程安全的; 相反,使用分割器的并行算法的实现应该确保分割器一次只被一个线程使用。 这通常是通过串行线程限制来获得的,这通常是通过递归分解工作的典型并行算法的自然结果。 调用trySplit()的线程可能会将返回的Spliterator移交给另一个线程,而该线程又可以遍历或进一步拆分该分割器。 如果两个或多个线程在同一个分割器上同时运行,则分割和遍历的行为是未定义的。 如果原始线程将一个分离器移离另一个线程进行处理,则最好是在tryAdvance()使用任何元素之前发生切换,因为某些保证(例如SIZED分配器SIZED准确性)仅在遍历开始之前有效。

    的原始亚型特Spliterator提供用于intlong ,和double值。 子类型默认实现为tryAdvance(java.util.function.Consumer)forEachRemaining(java.util.function.Consumer)框原始值到其对应的包装器类的实例。 这种拳击可能会破坏使用原始专长所获得的任何性能优势。 为了避免拳击,应该使用相应的基于图元的方法。 例如, Spliterator.OfInt.tryAdvance(java.util.function.IntConsumer)Spliterator.OfInt.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 s,用于遍历源的元素。 Spliterator API旨在通过支持分解和单元素迭代来支持除顺序遍历之外的有效并行遍历。 另外,用于通过分割器访问元件的协议被设计为比Iterator施加更小的每元件开销,并且避免为具有hasNext()next()单独方法所涉及的固有竞争。

    对于可变源,如果在Striterator绑定到其数据源的时间与遍历结束之间,源在结构上受到干扰(添加,替换或删除的元素),则可能会发生任意和非确定性行为。 例如,当使用java.util.stream框架时,这种干扰将产生任意的非确定性结果。

    源的结构干扰可以通过以下方式进行管理(大概顺序为减少的可取性):

    • 来源不能在结构上受到干扰。
      例如, CopyOnWriteArrayList一个实例是一个不可变的来源。 从源头创建的IMMUTABLE报告了IMMUTABLE的特征。
    • 源代码管理并发修改。
      例如, ConcurrentHashMap的密钥集是并发源。 从源创建的CONCURRENT报告了一个CONCURRENT的特征。
    • 可变源提供后期绑定和故障切换快速分割器。
      后期约束使窗口缩小,在此期间干扰可影响计算; 故障快速检测在尽力而为的基础上,遍历开始后发生结构性干扰,并抛出ConcurrentModificationException 例如, ArrayList和JDK中的许多其他非并发的Collection类,提供了后期绑定,故障快速拼接器。
    • 可变源提供了一个非后期绑定但是故障快速的分割器。
      由于潜在的干扰窗口较大,源会增加投掷ConcurrentModificationException的可能性。
    • 可变源提供后期绑定和非故障快速的分割器。
      由于没有检测到干扰,因此源头在穿越开始后会产生任意的非确定性行为。
    • 可变源提供非后期绑定和非故障快速的分割器。
      来源会增加任意非确定性行为的风险,因为在建设后可能会发生非检测到的干扰。

    例。 这是一个类(不是非常有用的,除了说明),它维护一个数组,其中实际数据保存在偶数位置,而不相关的标签数据保存在奇数位置。 它的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则在对原始子类型专用化进行操作时,如果出现基本值的 true则会报告诊断警告。
    从以下版本开始:
    1.8
    另请参见:
    Collection
    • Field Summary

      Fields  
      Modifier and Type Field 描述
      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
      特征值这标志着从产生的所有Spliterators trySplit()将是既 SIZEDSUBSIZED
    • 字段详细信息

      • DISTINCT

        static final int DISTINCT
        特性值这标志着,对于每对遇到的元件x, y!x.equals(y) 这适用于基于Set的Spliterator
        另请参见:
        Constant Field Values
      • SIZED

        static final int SIZED
        表示在遍历或分割之前从 estimateSize()返回的值的特征值表示在没有结构源修改的情况下表示完全遍历将遇到的元素数量的精确计数的有限大小。
        API Note:
        大多数集合的分割器,涵盖Collection所有元素报告此特征。 子分割器(例如HashSet的子分割器 )覆盖了一组子元素并近似于其报告的大小。
        另请参见:
        Constant Field Values
      • NONNULL

        static final int NONNULL
        特征值表示源保证遇到的元素不会是null (这适用于大多数并发集合,队列和映射)。
        另请参见:
        Constant Field Values
      • IMMUTABLE

        static final int IMMUTABLE
        特征值表示元素源不能在结构上进行修改; 也就是说,不能添加,替换或删除元素,因此在遍历过程中不会发生这种更改。 预计不会报告IMMUTABLECONCURRENT有关于在遍历期间检测到的结构性干扰的文档化策略(例如抛出ConcurrentModificationException )。
        另请参见:
        Constant Field Values
      • CONCURRENT

        static final int CONCURRENT
        特征值表示可以通过多个线程安全同时修改元素源(允许添加,替换和/或删除),而无需外部同步。 如果是这样,则Spliterator应该有一个关于在遍历期间修改影响的文件化策略。

        顶级Spliterator不应同时报告CONCURRENTSIZED ,因为如果已知的有限大小可能会在遍历期间同时修改源时发生更改。 这样的分割器是不一致的,并且不能保证使用该分割器的任何计算。 子分割器可能会报告SIZED如果子分割大小是已知的,并且在遍历时不反映源的添加或删除。

        顶级Spliterator不应同时报告CONCURRENTIMMUTABLE ,因为它们是互斥的。 这样的分割器是不一致的,并且不能保证使用该分割器的任何计算。 子程序可能会报告IMMUTABLE如果源的添加或删除在运行时不被反映。

        API Note:
        大多数并发收藏集保持一致性政策,保证在Spliterator构建点存在的元素的准确性,但可能不反映随后的添加或删除。
        另请参见:
        Constant Field Values
      • SUBSIZED

        static final int SUBSIZED
        特征值这标志着从产生的所有Spliterators trySplit()将是既SIZEDSUBSIZED (这意味着所有的子代码器,无论是直接还是间接,都将是SIZED

        根据SUBSIZED的要求不会报告SIZEDSUBSIZED不一致,并且不能保证使用该Spliterator的任何计算。

        API Note:
        一些拼接器,例如用于近似平衡的二叉树的顶级拼接器,将报告 SIZED而不是 SUBSIZED ,因为通常知道整个树的大小,但不知道子树的确切大小。
        另请参见:
        Constant Field Values
    • 方法详细信息

      • tryAdvance

        boolean tryAdvance​(Consumer<? super T> action)
        如果剩下的元素存在,执行给定的操作,返回true ; 否则返回false 如果此Spliterator是ORDERED ,则会按照遇到的顺序对下一个元素执行操作。 动作抛出的异常被转发给呼叫者。
        参数
        action - 动作
        结果
        false如果在进入此方法时不存在剩余元素,否则为 true
        异常
        NullPointerException - 如果指定的动作为空
      • forEachRemaining

        default void forEachRemaining​(Consumer<? super T> action)
        在当前线程中依次执行每个剩余元素的给定操作,直到所有元素都被处理或动作引发异常。 如果这个Spliterator是ORDERED ,操作将按照遇到的顺序执行。 动作抛出的异常被转发给呼叫者。
        实现要求:
        默认实现反复调用tryAdvance(java.util.function.Consumer<? super T>)直到它返回false 应尽可能覆盖。
        参数
        action - 行动
        异常
        NullPointerException - 如果指定的操作为空
      • trySplit

        Spliterator<T> trySplit​()
        如果此分割器可以被分区,返回一个包含元素的Spliter,当从该方法返回时,它不会被该Spliter所覆盖。

        如果此Spliterator是ORDERED ,则返回的Spliterator必须覆盖元素的严格前缀。

        除非这个Spliterator包含无数的元素,否则重复调用trySplit()必须最终返回null 非空返回:

        • 在拆分之前报告的值为estimateSize() ,拆分后必须大于或等于estimateSize()为此和返回的Spliterator;
        • 如果这Spliterator是SUBSIZED ,然后estimateSize()这个spliterator分裂之前必须等于总和estimateSize() ,这和拆分后返回Spliterator。

        该方法可能由于任何原因返回null ,包括空虚,遍历开始后无法拆分,数据结构约束和效率考虑。

        API Note:
        理想的trySplit方法(无遍历)将其元素精确地分成两半,从而实现平衡的并行计算。 许多离开这个理想的人仍然是非常有效的; 例如,仅近似分裂近似平衡的树,或者对于叶节点可以包含一个或两个元素的树,不能进一步分割这些节点。 然而,平衡和/或过度无效的trySplit力学的大偏差通常导致差的并行性能。
        结果
        一个 Spliterator涵盖了部分元素,或 null如果此拼接器无法拆分
      • estimateSize

        long estimateSize​()
        返回forEachRemaining(java.util.function.Consumer<? super T>)遍历将遇到的元素数量的估计值,如果无穷大,未知数或计算成本太高,则返回Long.MAX_VALUE

        如果此Spliterator是SIZED并且尚未部分遍历或拆分,或该Spliterator为SUBSIZED并且尚未部分遍历,则此估计必须是完整遍历将遇到的元素的精确计数。 否则,此估计可能是任意不准确的,但必须按照trySplit()调用指定的方式减少

        API Note:
        即使不精确的估计通常是有用的并且计算成本低廉。 例如,近似平衡的二叉树的子拼接器可以返回将元素的数量估计为其父代的数量的一半的值; 如果根分割器不能保持准确的计数,则可以将尺寸估计为对应于其最大深度的两倍。
        结果
        估计的大小,或 Long.MAX_VALUE如果无限,未知或太贵的计算。
      • getExactSizeIfKnown

        default long getExactSizeIfKnown​()
        方便的方法返回 estimateSize()如果这个Spliterator是 SIZED ,否则是 -1
        实现要求:
        如果Spliterator报告的特性为 SIZED ,则默认实现返回 estimateSize()的结果, estimateSize()返回 -1
        结果
        确切的大小,如果知道,其他 -1
      • characteristics

        int characteristics​()
        返回此Spliterator及其元素的一组特征。 结果从表示为或运算值ORDEREDDISTINCTSORTEDSIZEDNONNULLIMMUTABLECONCURRENTSUBSIZED 在给定的分配器之前或之前或之间调用trySplit重复调用characteristics()应始终返回相同的结果。

        如果Spliterator报告不一致的特征集(从单个调用返回的或多个调用返回的),则不能保证使用此Spliter的任何计算。

        API Note:
        分裂之前的给定分配器的特性可能与分裂后的特性不同。 对于具体的例子看到的特性值SIZEDSUBSIZEDCONCURRENT
        结果
        特征的表征
      • hasCharacteristics

        default boolean hasCharacteristics​(int characteristics)
        如果此Spliterator的 characteristics()包含所有给定的特征,则返回 true
        实现要求:
        如果给定特征的相应位被设置,默认实现将返回true。
        参数
        characteristics - 检查的特点
        结果
        true如果所有指定的特性都存在,否则为 false