According to the doc of Spliterator#getComparator, it states
If this Spliterator's source is
SORTEDby aComparator, returns thatComparator. If the source isSORTEDin natural order, returns null. Otherwise, if the source is notSORTED, throwsIllegalStateException.Implementation Requirements:
The default implementation always throws
IllegalStateException.Returns: a
Comparator, ornullif the elements are sorted in the natural order.Throws:
IllegalStateException- if the spliterator does not report a characteristic ofSORTED.
So when running 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 when doing 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 outputs 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 outputs false and throws an exception?
Shouldn't it give me the Comparator I supplied to sorted(), according to the documentation? 
(This happens also with reverseOrder(), or comparing(identity()), etc.).
Internally streams are using StreamOpFlag enum which is somewhat different from spliterator flags. Flags are converted using the java.util.stream.StreamOpFlag.fromCharacteristics(Spliterator<?>) method which implementation is the following:
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;
    }
}
Seems that internally the SORTED characteristic for the spliterator which is not explicitly natural ordered is unnecessary for the stream API, so it's not preserved. Actually it's never specified in the documentation that sorted(comparator).spliterator() must return the spliterator with SORTED characteristic. The spliterator documentation says that if it has SORTED characteristic, it must return the comparator, but there's no case when having the SORTED characteristic is required, thus it's up to implementation. This can change in future, but it's not a bug.
Update: just noticed that in JDK-9 there's a clear statement added into the documentation of spliterator() method:
The returned spliterator should report the set of characteristics derived from the stream pipeline (namely the characteristics derived from the stream source spliterator and the intermediate operations). Implementations may report a sub-set of those characteristics. For example, it may be too expensive to compute the entire set for some or all possible stream pipelines.
See the JDK-8048689 bug report.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With