Это слабое место в механизме определения типа компилятора. Чтобы определить тип uлямбды, необходимо установить целевой тип лямбды. Это осуществляется следующим образом. userList.sort()ожидает аргумент типа Comparator<User>. В первой строке Comparator.comparing()нужно вернуть Comparator<User>. Это означает , что Comparator.comparing()нуждается в Functionтом , что принимает Userаргумент. Таким образом, лямбда в первой строке uдолжна быть типа, Userи все работает.
Во второй и третьей строках целевой набор текста нарушается присутствием вызова reversed(). Я не совсем уверен, почему; и получатель, и тип возвращаемого значения reversed()таковы, Comparator<T>поэтому кажется, что целевой тип должен быть передан обратно получателю, но это не так. (Как я уже сказал, это слабость.)
Во второй строке ссылка на метод предоставляет дополнительную информацию о типе, которая заполняет этот пробел. Эта информация отсутствует в третьей строке, так что компилятор выводит uбыть Object(запасным вариантом логического вывода последней инстанции), которая выходит из строя.
Очевидно, что если вы можете использовать ссылку на метод, сделайте это, и это сработает. Иногда вы не можете использовать ссылку на метод, например, если вы хотите передать дополнительный параметр, поэтому вам нужно использовать лямбда-выражение. В этом случае вы должны указать явный тип параметра в лямбде:
userList.sort(Comparator.comparing((User u) -> u.getName()).reversed());
Возможно, компилятор будет расширен, чтобы охватить этот случай в будущем выпуске.