Java8 Null-safe сравнение

Возникли проблемы со сравнением двух продуктов. Я хочу сравнить винтажный (необязательный) атрибут каждого из них. Но всякий раз, когда этот атрибут имеет значение null, выдается NPE. Я думал, что с Comparator.nullsLast (..) я могу работать с нулевыми значениями ... Но, похоже, я либо неправильно понимаю, как это работает, либо что-то не так с кодом. Что мне нужно изменить, чтобы эта работа была нулевой?

@Override
public int compare(IProduct product1, IProduct product2) throws ProductComparisonException {

    Comparator<IShopProduct> comparator =
        Comparator.nullsLast(Comparator.comparing(IShopProduct::getVintage));

    return comparator.compare((IShopProduct)product1.getProvidedProductData(),
                              (IShopProduct)product2.getProvidedProductData());
}

заранее спасибо

есть ли шанс, что product1.getProvidedProductData() вернет null?

gvmani 07.05.2018 15:27

Ознакомьтесь со стандартным руководством по стилю Java. Люди с большей вероятностью помогут вам, если их не будут отвлекать идиосинкразические проблемы со стилем. В частности, ненужные пробелы и тот факт, что строка такая длинная, что мне приходится прокручивать по горизонтали

Novaterata 07.05.2018 15:49
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
8
2
2 959
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Так должно быть

Comparator<IShopProduct> comparator = 
            Comparator.comparing( IShopProduct::getVintage, 
                             Comparator.nullLast(naturalOrder()));

Comparator.nullFirst()/nullLast() считает, что нулевое значение больше / меньше, чем ненулевой объект

Редактировать

Это реализация Comparator.comparing ():

public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
        Function<? super T, ? extends U> keyExtractor)
{
    Objects.requireNonNull(keyExtractor);
    return (Comparator<T> & Serializable)
        (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
}

Как вы можете видеть, он вызывает keyExtractor.apply(c1).compareTo(), поэтому он выбрасывает NPE, если keyExtractor.apply(c1) - это null.

Предлагаемый мной код с использованием следующей функции:

public static <T, U> Comparator<T> comparing(
        Function<? super T, ? extends U> keyExtractor,
        Comparator<? super U> keyComparator)
{
    Objects.requireNonNull(keyExtractor);
    Objects.requireNonNull(keyComparator);
    return (Comparator<T> & Serializable)
        (c1, c2) -> keyComparator.compare(keyExtractor.apply(c1),
                                          keyExtractor.apply(c2));
}

Обычно он извлекает значение, а затем передает сравниваемые значения в Comparator.

Значения будут переданы в компаратор naturalOrder(), который разрешил value1.compareTo(value2). Обычно он выдает NPE, но мы обернули его Comparator.nullLast, у которого есть специальный обработчик null.

Спасибо! Почему мне нужен naturalOrder как второй параметр?

Remo 07.05.2018 15:45

Эта перегрузка метода сравнение вызовет исключение, если переданной функцией извлечения ключа является null или извлеченное свойство - null. Поскольку вы упомянули, что свойство vintage иногда может быть null, это является причиной исключения NullPointerException.

Альтернативой для решения этой проблемы является использование этого компаратора:

 Comparator<IShopProduct> comparator = 
      Comparator.comparing(IShopProduct::getVintage,
                Comparator.nullsLast(naturalOrder()));

Функция извлечения ключей, то есть IShopProduct::getVintage, используется для извлечения ключа сортировки.

Компаратор ключей, то есть Comparator.nullsLast(Comparator.naturalOrder()), используется для сравнения ключа сортировки.

Comparator.naturalOrder() здесь просто возвращает компаратор, который сравнивает объекты Comparable в естественном порядке.

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