Добрый день, друзья Java-разработчики!
Я знаю, что эта тема может быть немного, так in advance
как JDK8 еще не выпущен (и пока не во всяком случае ..), но я читал несколько статей о лямбда-выражениях и, в частности, части, связанной с новым API коллекции, известным как Stream.
Вот пример, приведенный в статье Java Magazine (это алгоритм популяции выдр ..):
Set<Otter> otters = getOtters();
System.out.println(otters.stream()
.filter(o -> !o.isWild())
.map(o -> o.getKeeper())
.filter(k -> k.isFemale())
.into(new ArrayList<>())
.size());
У меня вопрос: что произойдет, если в середине внутренней итерации Set одна из выдр будет равна нулю?
Я ожидал, что будет выброшено исключение NullPointerException, но, возможно, я все еще застрял в предыдущей парадигме разработки (нефункциональной), может ли кто-нибудь просветить меня, как с этим обращаться?
Если это действительно вызовет исключение NullPointerException, я считаю эту функцию довольно опасной и ее придется использовать только, как показано ниже:
- Разработчик, чтобы убедиться, что нет нулевого значения (возможно, используя предыдущий .filter (o -> o! = Null))
- Разработчик должен убедиться, что приложение никогда не генерирует null otter или специальный объект NullOtter, с которым нужно иметь дело.
Какой вариант лучше, или любой другой вариант?
Благодарность!
источник
filter(Objects::nonNull)
сObjects
отjava.utils
Ответы:
Текущее мышление, похоже, состоит в том, чтобы «терпеть» значения NULL, то есть разрешать их в целом, хотя некоторые операции менее терпимы и могут закончиться вызовом NPE. См. Обсуждение нулей в списке рассылки группы экспертов по лямбда-библиотекам, в частности это сообщение . Впоследствии был достигнут консенсус по варианту № 3 (с заметным возражением со стороны Дуга Ли). Так что да, обеспокоенность ОП по поводу взрыва трубопроводов с помощью NPE обоснована.
Недаром Тони Хоар называл нули «ошибкой на миллиард долларов». Работа с нулевыми значениями - настоящая боль. Даже с классическими коллекциями (без учета лямбда-выражений или потоков) пустые значения проблематичны. Как упоминалось в комментарии fge , некоторые коллекции допускают нули, а другие - нет. С коллекциями, допускающими значения NULL, это вносит двусмысленность в API. Например, с Map.get () возврат null указывает либо на то, что ключ присутствует и его значение равно null, либо на то, что ключ отсутствует. Чтобы устранить неоднозначность этих случаев, нужно проделать дополнительную работу.
Обычно значение null используется для обозначения отсутствия значения. Подход для решения этой проблемы, предложенный для Java SE 8, состоит в том, чтобы ввести новый
java.util.Optional
тип, который инкапсулирует наличие / отсутствие значения, а также поведение, заключающееся в предоставлении значения по умолчанию, или выдаче исключения, или вызове функции и т. Д., Если значение отсутствует.Optional
используется только новыми API, однако все остальное в системе все еще вынуждено мириться с возможностью обнуления.Мой совет - по возможности избегать фактических нулевых ссылок. Из приведенного примера трудно понять, как может существовать «нулевая» выдра. Но если это было необходимо, предложения OP по фильтрации нулевых значений или сопоставлению их с контрольным объектом ( шаблон нулевого объекта ) являются прекрасным подходом.
источник
null
отстой, вот почему. Соотв. в обзоре, который я видел (не могу найти), NPE - исключение номер 1 в Java. SQL не является языком программирования высокого уровня, уж точно не функциональным, который презирает null, поэтому ему все равно.Хотя ответы на 100% верны, небольшое предложение по улучшению
null
обработки регистра самого списка с помощью Optional :Эта часть
Optional.ofNullable(listOfStuff).orElseGet(Collections::emptyList)
позволит вамlistOfStuff
аккуратно обработать случай, когда значение равно null, и вернуть пустой список вместо сбоя с NullPointerException.источник
Ответ Стюарта дает прекрасное объяснение, но я хотел бы привести еще один пример.
Я столкнулся с этой проблемой при попытке выполнить в
reduce
Stream, содержащем нулевые значения (на самом деле это было такLongStream.average()
, что является типом уменьшения). Поскольку функция average () возвращаетсяOptionalDouble
, я предположил, что Stream может содержать значения NULL, но вместо этого было создано исключение NullPointerException. Это связано с объяснением Стюарта null v. Empty.Итак, как предлагает OP, я добавил такой фильтр:
list.stream() .filter(o -> o != null) .reduce(..);
Или, как указано ниже, используйте предикат, предоставляемый Java API:
Из обсуждения списка рассылки Стюарт связал: Брайан Гетц о нулях в Streams
источник
Если вы просто хотите отфильтровать нулевые значения из потока, вы можете просто использовать ссылку на метод java.util.Objects.nonNull (Object) . Из его документации:
Например:
List<String> list = Arrays.asList( null, "Foo", null, "Bar", null, null); list.stream() .filter( Objects::nonNull ) // <-- Filter out null values .forEach( System.out::println );
Это напечатает:
источник
Пример того, как избежать null, например, использовать фильтр перед группированием по
Отфильтруйте нулевые экземпляры перед groupingBy.
Вот примерMyObjectlist.stream() .filter(p -> p.getSomeInstance() != null) .collect(Collectors.groupingBy(MyObject::getSomeInstance));
источник