Getting a separator from a sorted stream throws an exception

According to the Spliterator#getComparator it points

If this Spliterator source is SORTED on a Comparator , returns this Comparator . If the source is SORTED in natural order, returns null. Otherwise, if the source is not SORTED , throws an IllegalStateException .

Implementation Requirements:

The default implementation always throws an IllegalStateException .

Returns: a Comparator or null if elements are sorted in a natural order.

Throws: IllegalStateException - if the delimiter does not report the SORTED characteristic.

So, when you run this piece of code

 Spliterator<Integer> spliterator = Stream.of(1, 2, 3).sorted().spliterator(); System.out.println((spliterator.characteristics() & Spliterator.SORTED) == Spliterator.SORTED); System.out.println(spliterator.getComparator()); 

I get:

 true null 

So far so good. Now with this:

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

It throws false and throws an exception:

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

Why does it throw false and throw an exception?

Should I not provide the Comparator that I provided sorted() as per the documentation?

(This also happens with reverseOrder() or comparing(identity()) , etc.).

+6
source share
2 answers

Internal streams use the StreamOpFlag enum, which is slightly different from spliterator flags. Flags are converted using the java.util.stream.StreamOpFlag.fromCharacteristics(Spliterator<?>) Method, the implementation of which is as follows:

 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; } } 

It seems that the API stream is not an explicitly SORTED attribute for a separator for a stream, which is not explicitly ordered, so it is not saved. In fact, he never indicated in the documentation that sorted(comparator).spliterator() should return a spliterator with the SORTED attribute. The spliterator documentation says that if it has a SORTED attribute, it should return a comparator, but there is no case where the SORTED attribute is SORTED , so it is before implementation. This may change in the future, but this is not a mistake.

Update: Just noticed that in JDK-9 a clear expression has been added to the spliterator() document, method:

The returned spliterator should report a set of characteristics obtained from the stream pipeline (namely, characteristics obtained from the stream source delimiter and intermediate operations). Implementations may report a subset of these characteristics. For example, it may be too expensive to compute the entire set for some or all of the possible stream pipelines.

See error report JDK-8048689 .

+1
source

I think this is a bug in Oracle JDK (1.8.0_45).

When you create a stream sorted using natural order with Stream#sorted() , it internally transfers the stream to SortedOps.OfRef using the following constructor:

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

When you give a custom Comparator with Stream#sorted(Comparator) , it does the same, but uses the following constructor instead:

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

StreamOpFlag.NOT_SORTED intended to clear the SORTED flag, if it was set earlier. This means that after this operation, the sorted stream will become an unordered stream.

I think that this could be used incorrectly instead of StreamOpFlag.IS_SORTED , and the call to super() should use the same parameters as in the first constructor.

I could not find the corresponding problem in the Java Bug System, but.

0
source

All Articles