According to the doc of Spliterator#getComparator
, it states
If this Spliterator's source is
SORTED
by aComparator
, returns thatComparator
. If the source isSORTED
in natural order, returns null. Otherwise, if the source is notSORTED
, throwsIllegalStateException
.Implementation Requirements:
The default implementation always throws
IllegalStateException
.Returns: a
Comparator
, ornull
if 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