从排序的流中获取spliterator会引发异常

use*_*315 6 java java-8 java-stream spliterator

根据文件Spliterator#getComparator,它说

如果此Spliterator的源是SORTEDa Comparator,则返回 Comparator.如果源是SORTED自然顺序,则返回null.否则,如果源不是SORTED,则抛出IllegalStateException.

实施要求:

始终抛出默认实现IllegalStateException.

返回:a Comparator,或者null元素是按自然顺序排序的.

抛出:IllegalStateException- 如果分裂器没有报告特征SORTED.

所以在运行这段代码时

Spliterator<Integer> spliterator = Stream.of(1, 2, 3).sorted().spliterator();

System.out.println((spliterator.characteristics() & Spliterator.SORTED) == Spliterator.SORTED);
System.out.println(spliterator.getComparator());
Run Code Online (Sandbox Code Playgroud)

我明白了:

true
null
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好.现在这样做:

Spliterator<Integer> spliterator = Stream.of(1, 2, 3).sorted(Comparator.naturalOrder()).spliterator();

System.out.println((spliterator.characteristics() & Spliterator.SORTED) == Spliterator.SORTED);
System.out.println(spliterator.getComparator());
Run Code Online (Sandbox Code Playgroud)

它输出false并抛出异常:

Exception in thread "main" java.lang.IllegalStateException
    at java.util.stream.StreamSpliterators$AbstractWrappingSpliterator.getComparator(StreamSpliterators.java:259)
    at SpliteratorTest.main(SpliteratorTest.java:10)
Run Code Online (Sandbox Code Playgroud)

为什么它输出false并抛出异常?

根据文件,它不应该给我Comparator提供给我的sorted()吗?

(这也发生在reverseOrder(),或comparing(identity())等).

Tag*_*eev 1

内部流使用StreamOpFlag枚举,这与 spliterator 标志有些不同。标志使用java.util.stream.StreamOpFlag.fromCharacteristics(Spliterator<?>)以下方法进行转换:

static int fromCharacteristics(Spliterator<?> spliterator) {
    int characteristics = spliterator.characteristics();
    if ((characteristics & Spliterator.SORTED) != 0 && spliterator.getComparator() != null) {
        // Do not propagate the SORTED characteristic if it does not correspond
        // to a natural sort order
        return characteristics & SPLITERATOR_CHARACTERISTICS_MASK & ~Spliterator.SORTED;
    }
    else {
        return characteristics & SPLITERATOR_CHARACTERISTICS_MASK;
    }
}
Run Code Online (Sandbox Code Playgroud)

似乎内部SORTED没有显式自然排序的 spliterator 特征对于流 API 来说是不必要的,因此不会保留它。实际上,文档中从未指定必须sorted(comparator).spliterator() 返回具有特征的分割器SORTED。spliterator 文档说,如果它具有SORTED特征,则必须返回比较器,但不存在SORTED需要具有特征的情况,因此取决于实现。这将来可能会改变,但这不是一个错误。

更新:刚刚注意到在 JDK-9 中,方法的文档中添加了spliterator()一条明确的声明:

返回的 spliterator 应该报告从流管道派生的特征集(即从流源 spliterator 和中间操作派生的特征)。实现可能会报告这些特征的子集。例如,计算一些或所有可能的流管道的整个集合可能太昂贵。

请参阅JDK-8048689错误报告。