Как работает цепочка методов в Java 8 Comparator? [дубликат]

этот вопрос уже есть ответ здесь:

Я готовлюсь к сертификату Java 8, и следующее меня озадачило littlebit, может быть, кто-то может мне помочь в этом? В Примере моделируется класс Squirrel. У него есть имя и вес. Теперь вы можете сделать класс Comparator для сортировки этой вещи, используя оба поля. Итак, сначала сортировать по имени, а затем по весу. Что-то вроде этого:--2-->

public class ChainingComparator implements Comparator<Squirrel> {
    public int compare(Squirrel s1, Squirrel s2) {

        Comparator<Squirrel> c = Comparator.comparing(s -> s.getSpecies());
        c = c.thenComparingInt(s -> s.getWeight());

        return c.compare(s1, s2);
    }
}

пока все хорошо.. но затем загадочная часть. Под примером кода они утверждают, что вы можете написать это в одной строке с помощью цепочки методов. Может быть, я неправильно понимаю, но когда я цепляю сравнение и thenComparing части, я получаю ошибку при компиляции. Это связано с типами сравниваемые объекты (первая строка, затем int).

почему он работает, когда я помещаю промежуточную переменную, а не при цепочке? А можно ли вообще цеплять?

2 ответов


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

укажите тип в параметре лямбда comparing() (или используйте ссылку на метод), и он решает проблему вывода Как возвращаемый тип comparing() может так быть выведено. :

    Comparator<Squirrel> c = Comparator.comparing((Squirrel s)  -> s.getSpecies())
                                       .thenComparingInt(s -> s.getWeight());

обратите внимание, что указание типа параметра лямбда thenComparingInt() (или с помощью ссылка на метод), такие как:

    Comparator<Squirrel> c = Comparator.comparing(s -> s.getSpecies())
                                       .thenComparingInt((Squirrel s) -> s.getWeight());

не будет работать в качестве приемника (здесь тип возврата цепного метода) не рассматривается в вычислении типа вывода.

этот учебник JDK 8 / документация объясняет это очень хорошо:

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


Да, возможно-цепь comparing(...) С thenComparing(...) и compare(...) использование ссылок на методы вместо лямбда-выражений:

public int compare(Squirrel s1, Squirrel s2) {
    return Comparator.comparing(Squirrel::getSpecies)
        .thenComparing(Squirrel::getWeight)
        .compare(s1, s2);
}

почему это работает таким образом? Я не могу объяснить это лучше, чем Брайан в его ответ на аналогичную вопрос.

кроме того, это можно переписать с помощью 1 строки (при условии, что у вас есть список белок, которые вы хотите отсортировать):

list.sort(Comparator.comparing(Squirrel::getSpecies).thenComparing(Squirrel::getWeight));