user2336315
user2336315

Reputation: 16067

Misunderstanding about Comparator in java 8

public class Test {
    public static void main(String[] args) {
        List<Pair<String, Integer>> list = new ArrayList<>();
        list.add(new Pair<>("1", 8));
        list.add(new Pair<>("3", 2));
        list.add(new Pair<>("2", 15));

        list.stream()
            .sorted(Comparator.comparingInt(p -> p.v))
            .map(p -> p.k)
            .forEach(System.out::println);

    }
}

class Pair<K, V> {
    K k;
    V v;
    public Pair(K k, V v) {
        this.k = k;
        this.v = v;
    }
}

Ok, as you understood this code is printing my pair keys from the lowest value associated to the highest so I get the expected output:

3 1 2

So far so good. Now I wanted to do the reverse, I thought I would only have to do

list.stream()
    .sorted(Comparator.comparingInt(p -> p.v).reversed())
    .map(p -> p.k)
    .forEach(System.out::println);

But I get a compilation error:

v cannot be resolved or is not a field

So it seems like comparingInt is returning a Comparator<Object>. Why it so? Shouldn't it return a Comparator<Integer> ?

These are both reproductible with Eclipse Luna version 1 and javac.

javac -version => 1.8.0
java  -version => java version "1.8.0_25"

Oh also feel free to change the title of my question is you find it too general, but I couldn't find the correct terms

Upvotes: 13

Views: 2933

Answers (1)

Jon Skeet
Jon Skeet

Reputation: 1502016

I believe it's just that type inference is failing, basically - because the reverse() call gets in the way of the expected argument type of sorted() and the lambda expression.

You can do it if you specify the type to comparingInt explicitly:

list.stream()
    .sorted(Comparator.<Pair<String, Integer>>comparingInt(p -> p.v).reversed())
    .map(p -> p.k)
    .forEach(System.out::println);

Or if you just declare the comparer first:

Comparator<Pair<String, Integer>> forward = Comparator.comparingInt(p -> p.v);
list.stream()
    .sorted(forward.reversed())
    .map(p -> p.k)
    .forEach(System.out::println);

It feels to me like there should be a Stream.reverseSorted so make this sort of thing really easy, but it doesn't look like it exists :(

Upvotes: 10

Related Questions