Comparator.reversed() не компилируется с использованием лямбда

У меня есть список с некоторыми объектами User, и я пытаюсь сортировать список, но работает только с помощью ссылки на метод, при выражении lambda компилятор дает ошибку:

List<User> userList = Arrays.asList(u1, u2, u3);
userList.sort(Comparator.comparing(u -> u.getName())); // works
userList.sort(Comparator.comparing(User::getName).reversed()); // works
userList.sort(Comparator.comparing(u -> u.getName()).reversed()); // Compiler error

Ошибка:

com\java8\collectionapi\CollectionTest.java:35: error: cannot find symbol
            userList.sort(Comparator.comparing(u -> u.getName()).reversed());
                                                     ^
symbol:   method getName()
location: variable u of type Object
1 error

Ответ 1

Это слабость в методе определения типа компилятора. Чтобы вывести тип u в лямбда, необходимо установить тип цели для лямбды. Это выполняется следующим образом. userList.sort() ожидает аргумент типа Comparator<User>. В первой строке Comparator.comparing() необходимо вернуть Comparator<User>. Это означает, что Comparator.comparing() требуется a Function, который принимает аргумент User. Таким образом, в лямбда на первой строке u должен иметь тип User и все работает.

Во второй и третьей строках целевой ввод прерывается присутствием вызова reversed(). Я не совсем понимаю, почему; как приемник, так и тип возврата reversed() равны Comparator<T>, поэтому кажется, что целевой тип должен быть передан обратно в приемник, но это не так. (Как я уже сказал, это слабость.)

Во второй строке ссылка на метод предоставляет дополнительную информацию о типе, которая заполняет этот пробел. Эта информация отсутствует в третьей строке, поэтому компилятор выводит u на Object (отступ от последней попытки), который не работает.

Очевидно, что если вы можете использовать ссылку на метод, сделайте это, и он будет работать. Иногда вы не можете использовать ссылку на метод, например, если вы хотите передать дополнительный параметр, поэтому вам нужно использовать выражение лямбда. В этом случае вы должны указать явный тип параметра в лямбда:

userList.sort(Comparator.comparing((User u) -> u.getName()).reversed());

Возможно, возможно, что компилятор будет расширен, чтобы охватить этот случай в будущей версии.

Ответ 2

Вы можете обойти это ограничение, используя два аргумента Comparator.comparing с Comparator.reverseOrder() в качестве второго аргумента:

users.sort(comparing(User::getName, reverseOrder()));

Ответ 3

users.sort(Comparator.comparing(User::getName));

-или же-

users.sort(Comparator.comparing(User::getName).reversed());