3

Spliterator interface defines a number of characteristics:

A Spliterator also reports a set of characteristics() of its structure, source, and elements from among ORDERED, DISTINCT, SORTED, SIZED, NONNULL, IMMUTABLE, CONCURRENT, and SUBSIZED.

Let's have a look at Sliterator#SORTED

Characteristic value signifying that encounter order follows a defined sort order.

Now let's have a look at some examples:

List.of(1,2,3,4,5).stream().spliterator().hasCharacteristics(Spliterator.SORTED)
$1 ==> false

the stream is not sorted, so Spliterator.SORTED should be false.

Let's sort the stream:

List.of(1,2,3,4,5).stream().sorted().spliterator()
                           .hasCharacteristics(Spliterator.SORTED)
$2 ==> true

The stream is sorted, Spliterator.SORTED should be true, no surprises here.

Let's finally sort the stream, but using a custom Comparator.

List.of(1,2,3,4,5).stream().sorted((a,b) -> a.compareTo(b))
                  .spliterator().hasCharacteristics(Spliterator.SORTED)
$3 ==> false

And I am completely lost here. Why Spliterator.SORTED is false in this case? The stream is sorted by with a custom comparator: .sorted((a,b) -> a.compareTo(b)), but SORTED flag is false. This seems illogical to me.

Let's image the following situation:

  List.of(1,2,3,4).stream()
1:                .sorted() // SORTED flag is set to true
2:                .filter(i -> i % 2 == 0) // Operation which doesn't reset SORTED
3:                .sorted() // can be ignored
4:                .forEach(System.out::println)

there are 3 intermediate operations in the stream pipeline: two sorted and filter. On line 1: stream is sorted, on line 2: the stream is filtered and Spliterator.SORTED is still true. This means that on the sorted operation on line 3: can be ignored (has been already sorted on line 1 and SORTED flag is true.

However when sorted with comparator is used -> every call to sorted will be executed even if compatator is the same:

List.of(1,2,3,4).stream()
                .sorted(Comparator.reverseOrder()) // SORTED flag is not affected
                .filter(i -> i % 2 == 0)
                .sorted(Comparator.reverseOrder()) // will be sorted one more time
                .forEach(System.out::println)

It might be that I misunderstood the javadocs, but still this seems strange and illogical.

Anton Balaniuc
  • 10,889
  • 1
  • 35
  • 53
  • 2
    this is an exact duplicate of the answer I already gave btw :) thus deleted my answer – Eugene Jun 01 '18 at 11:31
  • 2
    just be sure to read the comments! that `Spliterator#getComparator` last comment... – Eugene Jun 01 '18 at 11:34
  • @Eugene, thanks a lot. Still this is a bit strange. I am curious if this will be changed in the future java releases. – Anton Balaniuc Jun 01 '18 at 11:45
  • well, I am not the person to ask this :| but yes, I am very interested also – Eugene Jun 01 '18 at 11:47
  • As explained [here](https://stackoverflow.com/a/46649315/2711488) and [here](https://stackoverflow.com/a/46712958/2711488), when you request a spliterator from a stream with intermediate operations, .i.e don't get the source spliterator, you will get a wrapper spliterator which will convert the stream state flags to characteristics, but the pipeline nodes only maintain flags the implementation actively uses. And sorted with custom comparator is not used. All other characteristics are lost. – Holger Jun 01 '18 at 13:21

0 Answers0