7

根据 的文档Spliterator#getComparator,它指出

如果此 Spliterator 的来源是SORTEDa Comparator,则返回 that 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());

我得到:

true
null

到目前为止,一切都很好。现在这样做时:

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());

它输出false并抛出异常:

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

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

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

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

4

2 回答 2

1

内部流使用StreamOpFlag枚举,这与拆分器标志有些不同。使用实现如下的方法转换标志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;
    }
}

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

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

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

请参阅JDK-8048689错误报告。

于 2015-07-01T11:00:55.253 回答
0

我认为这是 Oracle JDK (1.8.0_45) 中的一个错误。

当您使用自然顺序对流进行排序时,它会使用以下构造函数Stream#sorted()在内部将流包装在 a中:SortedOps.OfRef

    OfRef(AbstractPipeline<?, T, ?> upstream) {
        super(upstream, StreamShape.REFERENCE,
              StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SORTED);
    ...

当您使用 with 进行自定义ComparatorStream#sorted(Comparator),它会执行相同的操作,但会使用以下构造函数:

    OfRef(AbstractPipeline<?, T, ?> upstream, Comparator<? super T> comparator) {
        super(upstream, StreamShape.REFERENCE,
              StreamOpFlag.IS_ORDERED | StreamOpFlag.NOT_SORTED);
    ...

StreamOpFlag.NOT_SORTED旨在清除标志,SORTED以防之前设置。这意味着经过此操作后,已排序的流将变为未排序的流。

我认为它可能已被滥用,StreamOpFlag.IS_SORTED并且super()调用应该使用与第一个构造函数中相同的参数。

不过,我在 Java Bug System 中找不到相应的问题。

于 2015-07-01T13:21:26.317 回答