1

Can anyone please help me understand why does the below method reference works with thenComparing method:

List<Person> li = personList.stream()
                .sorted(Comparator.comparing(Person::getAge).thenComparing(Person::getName))
                .collect(Collectors.toList());

But when I am trying to do it using a lambda expression, it doesn't work. Here, I am getting a compilation error - "Cannot resolve method getAge in 'Object'" :

List<Person> li = personList.stream()
                .sorted(Comparator.comparing(person -> person.getAge()).thenComparing(person -> person.getName()))
                .collect(Collectors.toList());

Moreover, I can see that if I remove the thenComparing method, then this code again works with lambda expression:

List<Person> li = personList.stream()
                .sorted(Comparator.comparing(person -> person.getAge()))
                .collect(Collectors.toList());

Can you please let me know where I am going wrong?

the_novice
  • 105
  • 7

1 Answers1

2

The problem is with this expression:

Comparator.comparing(person -> person.getAge()).thenComparing(person -> person.getName())

In the first part Comparator.comparing(person -> person.getAge()), the compiler is not able to infer the type of the lambda argument as Person, because the expression is not assigned to a variable that helps infer that information.

On the other hand, when removing the thenComparing() part, the compiler can infer the type of the lambda argument, because the comparator Comparator.comparing(person -> person.getAge()) is targeted as argument to the sorted() method, which is being invoked on a Stream<Person>.

Note that if you explicitly specify the type of the argument, it works:

Comparator.comparing((Person person) -> person.getAge()).thenComparing(person -> person.getName())
M A
  • 71,713
  • 13
  • 134
  • 174
  • Got it. Does this mean, it is always better to specify the type of argument? And is it a shortcoming of streams that if we use the thenComparing() part then it's not able to infer the type of the argument? Or is this the expected behavior? – the_novice Feb 18 '21 at 17:00
  • @the_novice This is not related to streams, but rather to how generics work (generic type inference). In this case adding an explicit type to the lambda arg helps the compiler in inferring the correct type, but normally we don't need to explicitly specify it: the problem in this case is that the compiler was not able to automatically infer because there was a chain of two comparator expressions. – M A Feb 18 '21 at 17:27