Jest to słabość mechanizmu wnioskowania typu kompilatora. Aby wywnioskować typ u
lambda, należy ustalić typ docelowy dla lambda. Jest to realizowane w następujący sposób. userList.sort()
oczekuje argumentu typu Comparator<User>
. W pierwszym wierszu Comparator.comparing()
musi wrócić Comparator<User>
. Oznacza to, że Comparator.comparing()
potrzebuje Function
że bierze User
argument. Stąd w lambdzie w pierwszym wierszu u
musi być typu User
i wszystko działa.
W drugim i trzecim wierszu pisanie docelowe jest zakłócane przez obecność wywołania reversed()
. Nie jestem do końca pewien, dlaczego; zarówno odbiornik, jak i zwracany typ reversed()
są, Comparator<T>
więc wydaje się, że typ docelowy powinien być propagowany z powrotem do odbiorcy, ale tak nie jest. (Jak powiedziałem, to słabość.)
W drugim wierszu odwołanie do metody zawiera dodatkowe informacje o typie, które wypełniają tę lukę. Tych informacji nie ma w trzeciej linii, więc kompilator wnioskuje, u
że jest Object
(ostatnia deska ratunku), co kończy się niepowodzeniem.
Oczywiście, jeśli możesz użyć odwołania do metody, zrób to i zadziała. Czasami nie możesz użyć odwołania do metody, np. Jeśli chcesz przekazać dodatkowy parametr, więc musisz użyć wyrażenia lambda. W takim przypadku należałoby podać jawny typ parametru w parametrze lambda:
userList.sort(Comparator.comparing((User u) -> u.getName()).reversed());
Może być możliwe ulepszenie kompilatora, aby uwzględnić ten przypadek w przyszłej wersji.