哪些流操作使用CONCURRENT
,IMMUTABLE
和NONNULL
Spliterator 特征?他们每个人如何帮助这些操作?
我不是在问那些标志是什么,这可以在文档中很容易地找到。我在问哪些操作使用它们以及如何使用它们。
哪些流操作使用CONCURRENT
,IMMUTABLE
和NONNULL
Spliterator 特征?他们每个人如何帮助这些操作?
我不是在问那些标志是什么,这可以在文档中很容易地找到。我在问哪些操作使用它们以及如何使用它们。
首先,您应该明确区分您在Spliterator
这里询问的特征,这些特征取决于 Stream 的来源;因为还有 ( CONCURRENT
,UNORDERED
和IDENTITY_FINISH
例如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
报告IMMUTABLE
和ConcurrentHashMap
报告)。NONNULL
另一方面,这些标志可以在将来使用 - 如果您知道源不能包含 null 元素 ( NONNULL
),显然您可以跳过一些 null 检查或使用 null 定义某些状态。我想不出CONCURRENT
or的任何例子IMMUTABLE
,但可能有这样的例子。
例如,在一个UNORDERED
和CONCURRENT
收集器(!=Spliterator
属性)的当前实现下,combiner
当你这样做时不会调用toConcurrentMap
。例如:
Set.of("one", "two", "das", "dasda")
.stream()
.parallel()
.collect(Collectors.toConcurrentMap(Function.identity(), String::length));
不会调用combiner
- 因为没有必要。
可以针对您提到的 3 个特征中的任何一个进行此类优化。例如,您可以阅读this where StreamOpFlag.ORDERED
has changed the result findFirst
in java 8 vs java 9
在 Java 8 中,流操作不使用这 3 个特性。这可以通过在 Java 源代码中搜索这些常量来检查。
但是,CONCURRENT
当您编写自己的集合时,该特性可能会影响并行流的行为。如果您Spliterator
从集合创建一个而不报告CONCURRENT
特征,那么拆分器将另外具有SIZED
和SUBSIZED
特征:
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
未并行化SIZED
且SUBSIZED
并行性较差的拆分器,因此当您编写自己的并发集合时,最好编写自定义拆分器而不依赖默认拆分器实现。
人们说IMMUTABLE
没有使用,但事实证明,Stream#iterate
报告IMMUTABLE
:
jshell> Stream.iterate(0, i -> i + 1).spliterator().characteristics()
$1 ==> 1040
1040 是IMMUTABLE | ORDERED
,但它看起来像任何操作都会丢弃IMMUTABLE
(使用map
, filter
, flatMap
, limit
, skip
; 在 Java 16 上测试)
IntStream#iterate
,LongStream#iterate
并且DoubleStream#iterate
报告NONNULL
也是如此,但下一个操作也会丢弃。