哪些流操作使用 `CONCURRENT`、`IMMUTABLE` 和 `NONNULL` Spliterator 特性?

Which stream operations use `CONCURRENT`,`IMMUTABLE` and `NONNULL` Spliterator characteristics?

哪些流操作使用 CONCURRENTIMMUTABLENONNULL Spliterator 特性?他们每个人如何帮助这些行动?


我不是在问那些标志是什么,这可以在文档中轻松找到。我在问哪些操作使用它们以及如何使用它们。

在Java8中,流操作没有使用这3个特性。这可以通过在 Java 来源中搜索这些常量来检查。

但是,当您编写自己的集合时,CONCURRENT 特性可能会影响并行流的行为。如果您从集合创建 Spliterator 并且 报告 CONCURRENT 特征,则拆分器将另外具有 SIZEDSUBSIZED特征:

Collection<Integer> col = ...
Spliterator<Integer> s = Spliterators.spliterator(col, 0);

System.out.println(s.hasCharacteristics(Spliterator.SIZED)); // Prints true
System.out.println(s.hasCharacteristics(Spliterator.SUBSIZED)); // Prints true

但是如果你报告 CONCURRENT 特性,那么拆分器就不再是 SIZED:

Collection<Integer> col = ...
Spliterator<Integer> s = Spliterators.spliterator(col, Spliterator.CONCURRENT);

System.out.println(s.hasCharacteristics(Spliterator.SIZED)); // Prints false
System.out.println(s.hasCharacteristics(Spliterator.SUBSIZED)); // Prints false

不是 SIZEDSUBSIZED 的拆分器并行化很差,因此当您编写自己的并发集合时,最好编写自定义拆分器而不是依赖默认拆分器实现。

首先要明确区分,你这里问的Spliterator特性和这些依赖于Stream的source;因为还有(例如 CONCURRENTUNORDEREDIDENTITY_FINISH for Collectors)。

StreamOpFlag中有评论说:

// The following Spliterator characteristics are not currently used but a
// gap in the bit set is deliberately retained to enable corresponding
// stream flags if//when required without modification to other flag values.
//
// 4, 0x00000100 NONNULL(4, ...
// 5, 0x00000400 IMMUTABLE(5, ...
// 6, 0x00001000 CONCURRENT(6, ...
// 7, 0x00004000 SUBSIZED(7, ...

据我了解,这些并不是与 Spliterator 中的直接一对一映射,但仍未使用。

目前(我已经搜索了 jdk-8 和 9 来源),两者都没有被利用 - 但仍然被 Spliterators 的一些实现所报告(例如,Arrays 报告 IMMUTABLEConcurrentHashMap 报告 NONNULL)。

另一方面,这些标志可以在将来使用 - 如果您知道源不能包含空元素 (NONNULL),显然您可以跳过一些空检查或定义 一些状态 为空。我想不出 CONCURRENTIMMUTABLE 的任何示例,但可能有这样的示例。

例如,在 UNORDEREDCONCURRENT 收集器(!= Spliterator 属性)的当前实现下,当您执行 toConcurrentMap。例如:

Set.of("one", "two", "das", "dasda")
            .stream()
            .parallel()
            .collect(Collectors.toConcurrentMap(Function.identity(), String::length));

不会调用 combiner - 因为没有必要。

可以针对您提到的 3 个特征中的任何一个进行此类优化。例如,您可以阅读 this,其中 StreamOpFlag.ORDERED 在 java 8 与 java 9

中更改了 findFirst 的结果

人们说 IMMUTABLE 没有被使用,但事实证明,Stream#iterate 报告 IMMUTABLE:

jshell> Stream.iterate(0, i -> i + 1).spliterator().characteristics()
 ==> 1040

1040 是 IMMUTABLE | ORDERED 但看起来任何操作都会掉落 IMMUTABLE(使用 mapfilterflatMaplimit 进行测试, skip;在 Java 16)
上测试 IntStream#iterateLongStream#iterateDoubleStream#iterate 也报告 NONNULL,但下一个操作也会将其删除。