Как работает цепочка методов в Java 8 Comparator?

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

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, я получаю ошибку компиляции. Это связано с типами сравниваемых объектов (сначала String, затем int).

Почему это работает, когда я добавляю промежуточную переменную, а не при связывании? И возможно ли вообще цепочка?

попробуйте этот `Comparator <Squirrel> c = Comparator.comparing ((Squirrel s) -> s.getSpecies ()). thenComparingInt (s -> s.getWeight ());`

SEY_91 24.03.2018 21:52
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
9
1
800
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

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

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

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

list.sort(Comparator.comparing(Squirrel::getSpecies).thenComparing(Squirrel::getWeight));
Ответ принят как подходящий

При объединении обоих в цепочку компилятор не может вывести аргумент типа возвращаемого компаратора 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 очень хорошо это объясняет:

Note: It is important to note that the inference algorithm uses only invocation arguments, target types, and possibly an obvious expected return type to infer types. The inference algorithm does not use results from later in the program.

Другие вопросы по теме