Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stream characteristics for the streams generated for SortedMap may not be SORTED if created with custom Comparator

Mastering Lambdas by Maurice Naftalin, Ch6 - Stream Performance.

There is explanation about the different characteristics of streams at the different stages of execution(intermediate & terminal). For eg.

Stream.of(8,3,5,6,7,4)//ORDERED, SIZED
.filer(i->i%2==0) // ORDERED
.sorted() // ORDERED, SORTED
.distinct() // DISTINCT, ORDERED, SORTED
.map(i->i+1) // ORDERED
.unordered(); //none

What was confusing to me was explanation of SORTED characteristics :

"Stream elements may have been sorted in other orders if a Comparator has been defined and used for the purpose, but such streams do not have the SORTED characteristic."

Why if the custom comparator is provided for the implementation of Sorted Data Structure(SortedMap in above case) the framework would not consider creating streams with SORTED characteristic?

like image 327
Chota Bheem Avatar asked Jun 11 '17 16:06

Chota Bheem


1 Answers

Flown is absolutely correct in his comment. SORTED is only reported for natural order and this has been debated before. First this is even internally used as a flag called: isNaturalSort:

/**
     * Sort using natural order of {@literal <T>} which must be
     * {@code Comparable}.
     */
    OfRef(AbstractPipeline<?, T, ?> upstream) {
        super(upstream, StreamShape.REFERENCE,
              StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SORTED);
        this.isNaturalSort = true;

The same flag isNaturalSort is set to false when used via sorted(CustomComparator).

This is an internal details and it seems that the jdk developers did not find useful to implemented it as such - there was probably nothing to do with it that could be really useful. But this might change...

There is at least one flaw here still. Imagine a class like this:

static class User implements Comparable<User> {
    private final int id;

    public User(int id) {
        super();
        this.id = id;
    }

    public int getId() {
        return id;
    }

    @Override
    public int compareTo(User usr) {
        return 42; // don't do this
    }

}

And some stream operations:

Stream<User> byId = Stream.of(new User(12), new User(10))
            .sorted(Comparator.comparing(User::getId));

System.out.println(byId.spliterator().hasCharacteristics(Spliterator.SORTED));

Stream<User> natural = Stream.of(new User(12), new User(10))
            .sorted(Comparator.naturalOrder());

System.out.println(natural.spliterator().hasCharacteristics(Spliterator.SORTED)); 

Stream<User> plain = Stream.of(new User(12), new User(10)).sorted();
System.out.println(plain.spliterator().hasCharacteristics(Spliterator.SORTED));

The first two report false, but the last one reports true; which is at least weird.

like image 135
Eugene Avatar answered Oct 20 '22 23:10

Eugene