Reputation: 227
I have few questions for the following code sample.
class HypotheticComparators {
class Pair<U,T> {
private U left;
private T right;
public U getLeft() {
return left
}
public T getRight() {
return right;
}
}
class User {
private String name;
private Integer age;
public String getName(){
return name;
}
public Integer getAge() {
return age;
}
}
public static void main(String[] args){
List<Pair<LocalDate,LocalDate>> dataIntevals = new ArrayList<>();
//Doesn't Compile
Comparator<Pair<LocalDate,LocalDate>> pairComparator1 = Comparator.comparing(Pair::getLeft).thenComparing(Pair::getRight);
//This Compile
Comparator<Pair<LocalDate,LocalDate>> leftComparator = Comparator.comparing(Pair::getLeft);
Comparator<Pair<LocalDate,LocalDate>> pairComparator2 = leftComparator.thenComparing(Pair::getRight));
//This compile
Comparator<User> userComparator1 = Comparator.comparing(User::getName).thenComparing(User::getAge);
//This also compile
Comparator<User> userNameComparator = Comparator.comparing(User::getName);
Comparator<User> userComparator2 = userNameComparator.thenComparing(User::getAge);
}
}
For this statement, Comparator<Pair<LocalDate,LocalDate>> pairComparator1 = Comparator.comparing(Pair::getLeft).thenComparing(Pair::getRight);
, My initial idea of why it does not compile is that themComparaing
cannot infer type from Comparator.comparing(Pair::getLeft)
. But i am not convinced by this idea beacuase looking at the source code of Comparator.comparing
and thenComparing
public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
Function<? super T, ? extends U> keyExtractor)
{
Objects.requireNonNull(keyExtractor);
return (Comparator<T> & Serializable)
(c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
}
default <U extends Comparable<? super U>> Comparator<T> thenComparing(
Function<? super T, ? extends U> keyExtractor)
{
return thenComparing(comparing(keyExtractor));
}
Comparator.comparing(Pair::getLeft)
can have type inference with T as Pair<LocalDate, LocalDate>
, themComparing
can also have a type inference with T as Pair<LocalDate, LocalDate>
. Furthermore, if my idea is correct, why Comparator<User> userNameComparator = Comparator.comparing(User::getName);
can compile without any problem. Am i missing anything here ?
Upvotes: 3
Views: 305
Reputation: 438
The reason that the compiler can't infer the type of Pair::getLeft
in the first case, but can in the second case, is because it uses the type of the variable to infer the type, but because you call thenComparing()
right away, it doesn't have access to this information.
You can check this by having Comparator.comparing(Pair::getLeft);
by itself on a new line, without saving it to a variable. The compiler will fail to infer the type.
This can be resolved by explicitly saying Pair<LocalDate,LocalDate>::getLeft
.
Upvotes: 0
Reputation: 5225
The Java type-inferer can't be sure that the first .comparing
is going to be accepting the same type that the second one is, so it guesses that the types for the first method are Object, Pair<LocalDate, LocalDate>
, and Object doesn't implement Comparable. You can work around this by specifying the generic types for the method:
Comparator<Pair<LocalDate,LocalDate>> pairComparator1 = Comparator
.<Pair<LocalDate, LocalDate>, LocalDate>comparing(Pair::getLeft)
.thenComparing(Pair::getRight);
Upvotes: 2