Alguém pode explicar a diferença entre seguir variantes do complexo Comparator
s?
List<String> listOfStrings = Arrays.asList("algo", "test", "is", "a", "common");
listOfStrings.stream()
.sorted(Comparator.comparingInt(String::length).thenComparing(Comparator.naturalOrder()))
.sorted(Comparator.naturalOrder().thenComparing(Comparator.comparingInt(String::length))
.forEach(System.out::println);
Por primeira chamada sorted
é OK, enquanto o segundo não se pode sequer compilar?
O compilador sabe que Comparator.comparingInt(String::length)
retorna um Comparator<String>
(desde que você está passando um ToIntFunction<String>
a ele), e, portanto, espera que o segundo Comparator
, passado para thenComparing
, para ser um Comparator<String>
, para que ele possa inferir o tipo do Comparator
retornado por Comparator.naturalOrder()
ser um Comparator<String>
.
Por outro lado, quando o primeiro Comparator
é retornado por Comparator.naturalOrder()
(que retorna a Comparator<T>
), o compilador não sabe que tipo de Comparator
esperar para o argumento de thenComparing
, por isso rejeita o Comparator<String>
passado para ele.
Este erro pode ser evitado se você declarar o tipo de Comparator
retornado por Comparator.naturalOrder()
explicitamente:
Comparator<String> comp = Comparator.naturalOrder();
listOfStrings.stream()
.sorted(comp.thenComparing(Comparator.comparingInt(String::length)))
.forEach(System.out::println);