Работа с нулевым атрибутом с использованием потоков Java 8 и сортировка с использованием лямбда-выражений

Давайте рассмотрим класс Parent, который содержит только один атрибут Integer. Я создал 6 объектов родительского класса, а значения атрибута равны 100, 20, 300, 400, 500, null.

Теперь я добавил все объекты в список (имя списка — список). Затем я хочу получить объекты, значение атрибута которых больше 100. Для этой цели я использовал потоки Java 8.

Predicate<Entity> predicate = e -> e.getParentId() < 100;
result = list.stream().filter(predicate).collect(Collectors.toList());

Я также хочу отсортировать список в порядке убывания. Для этой цели я использовал следующий код.

Comparator<Entity> comp = (d1,d2) -> d2.getId().compareTo(d1.getId());
list.sort(comp);

В обоих случаях я получаю NullPointerException.

Как справиться с этим?


person Manu Joy    schedule 08.07.2015    source источник


Ответы (6)


Все ответы здесь вращаются вокруг «выбросить плохие элементы, те, у которых есть нуль getParentId()». Это может быть ответом, если они действительно плохие. Но есть еще одна альтернатива: Comparators.nullsFirst (или последняя). Это позволяет вам сравнивать вещи, рассматривающие нулевое значение как меньшее (или большее) всех ненулевых значений, поэтому вам не нужно выбрасывать элементы с нулевым parentId прочь.

Comparator<Entity> cmp = nullsLast(comparing(Entity::getParentId));
List<Entity> list = list.stream().sorted(cmp).collect(toList());

Вы можете сделать то же самое для фильтрации; определите свой предикат как:

Predicate<Entity> predicate = e -> e.getParentId() != null 
                                       && e.getParentId() < 100;
person Brian Goetz    schedule 08.07.2015
comment
Я думаю, вы имели в виду Comparator.nullsFirst, потому что Comparators из Гуавы - person Eugene Kortov; 10.09.2019

Похоже, вы ищете что-то вроде:

list.sort(Comparator.comparing(Entity::getParent, 
                               Comparator.nullsLast(Integer::compareTo)));

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

person joetde    schedule 02.06.2016
comment
это решение сработало для меня. Потому что я не хочу фильтровать нулевые значения. - person omerhakanbilici; 14.11.2016
comment
Спасибо, что показали, как использовать Comparator.nullsLast. - person Noumenon; 01.12.2018

Попробуйте выполнить предварительную фильтрацию только для ненулевых значений parentId:

result = list.stream().filter(e -> e.getParentId() != null).filter(predicate).collect(Collectors.toList());

[править] Только что увидел, что атрибут (e.parentId) кажется null. В этом случае вторая вещь, сортировка, ломается. Вы сортируете исходный список, а не отфильтрованный. Попробуйте result.sort(comp), тогда вам следует избегать NPE.

person Dominik Sandjaja    schedule 08.07.2015
comment
Это должно работать. Вы также можете сделать .filter(Objects::nonNull) - person Nir Alfasi; 08.07.2015
comment
Проблема в том, что объект не нулевой, но атрибут нулевой, если мой содержит 100 атрибутов, и я создал список этих объектов, в котором многие атрибуты могут иметь нулевое значение в некоторых объектах в списке, как мне обрабатывать это. - person Manu Joy; 08.07.2015

Вы можете сделать все это в одном конвейере Stream:

List<Entity> result =  
    list.stream()
        .filter(e -> e.getParentId()!=null) // it's not clear if the null
                                            // is the Entity object itself
                                            // (in which case it should be e!=null)
                                            // or just the ParentId member
        .filter(predicate)
        .sorted(comp)
        .collect(Collectors.toList());

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

Predicate<Entity> predicate = e -> e.getParentId() > 100; // not < 100
person Eran    schedule 08.07.2015
comment
Разве этот фильтр не отфильтрует e.getParentId() == null элементов? Он говорит о том, что e является нулевым. - person Codebender; 08.07.2015
comment
@Codebender Возможно, я неправильно понял вопрос, но казалось, что OP создал объекты с родительскими идентификаторами 100,20,300,400,500,null, поэтому я предположил, что нуль относится к ParentId. Я могу быть не прав. - person Eran; 08.07.2015
comment
@Codebender, это не ясно. Я думаю, он говорит о том, что parentId равен нулю, что возможно, если это Integer. - person ajb; 08.07.2015

Используйте возможности ссылки на методы, чтобы сделать код еще более компактным:

   List<Entity> result =
            list.stream()
                    .filter(Objects::nonNull) 
                    .filter(predicate)
                    .sorted(comp)
                    .collect(Collectors.toList());
person Fritz Duchardt    schedule 08.07.2015

Ты можешь сделать:

Predicate<Entity> predicate = e -> e.getParentId() < 100;
Predicate<Entity> nonNull = e -> e != null;
result = list.stream().filter(nonNull)
                      .filter(predicate)
                      .collect(Collectors.toList());

Конечно, вы можете объединить предикаты в один, но я добавил второй для лучшей читабельности. Кроме того, вы можете изменить предикат nonNull, чтобы проверить либо всю сущность, либо только атрибут id (или даже оба). Просто немного поиграйте с ним. :)

person Konstantin Yovkov    schedule 08.07.2015