Перейти к основному содержимому

Null-Safe потоки Java из коллекций

· 4 мин. чтения

1. Обзор

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

Начнем с того, что для полного понимания этого материала требуется некоторое знакомство со справочниками по методам Java 8, лямбда-выражениями, необязательными и потоковыми API.

Если вы не знакомы с какой-либо из этих тем, сначала ознакомьтесь с нашими предыдущими статьями: Новые функции в Java 8 , Руководство по Java 8 (необязательно) и Введение в потоки Java 8 .

2. Зависимость от Maven

Прежде чем мы начнем, есть одна зависимость Maven, которая нам понадобится для определенных сценариев:

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.2</version>
</dependency>

Библиотеку commons-collections4 можно загрузить с Maven Central.

3. Создание потоков из коллекций

Основной подход к созданию Stream из коллекции любого типа заключается в вызове методов stream() или parallelStream() для коллекции в зависимости от требуемого типа потока:

Collection<String> collection = Arrays.asList("a", "b", "c");
Stream<String> streamOfCollection = collection.stream();

Наша коллекция, скорее всего, в какой-то момент будет иметь внешний источник, мы, вероятно, получим метод, аналогичный приведенному ниже, при создании потоков из коллекций:

public Stream<String> collectionAsStream(Collection<String> collection) {
return collection.stream();
}

Это может вызвать некоторые проблемы. Когда предоставленная коллекция указывает на нулевую ссылку, код во время выполнения выдает исключение NullPointerException .

В следующем разделе рассматриваются способы защиты от этого.

4. Делаем созданные потоки коллекций Null-Safe

4.1. Добавьте проверки, чтобы предотвратить нулевые разыменования

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

Stream<String> collectionAsStream(Collection<String> collection) {
return collection == null
? Stream.empty()
: collection.stream();
}

Однако у этого метода есть несколько проблем.

Во-первых, нулевая проверка мешает бизнес-логике, снижая общую читабельность программы.

Во-вторых, использование null для представления отсутствия значения считается неправильным подходом после Java SE 8: существует лучший способ смоделировать отсутствие и наличие значения.

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

4.2. Используйте метод emptyIfNull из библиотеки CollectionUtils .

Мы можем использовать библиотеку CollectionUtils Apache Commons, чтобы убедиться, что наш поток является нулевым . Эта библиотека предоставляет метод emptyIfNull , который возвращает неизменяемую пустую коллекцию с нулевой коллекцией в качестве аргумента или саму коллекцию в противном случае:

public Stream<String> collectionAsStream(Collection<String> collection) {
return emptyIfNull(collection).stream();
}

Это очень простая стратегия. Однако это зависит от внешней библиотеки. Если политика разработки программного обеспечения ограничивает использование такой библиотеки, то это решение становится недействительным .

4.3. Используйте необязательный Java 8

Необязательный Java SE 8 — это контейнер с одним значением, который либо содержит значение, либо нет. Если значение отсутствует, опциональный контейнер считается пустым.

Использование Необязательно можно считать лучшей общей стратегией для создания нулевой коллекции из потока.

Давайте посмотрим, как мы можем его использовать, а затем краткое обсуждение ниже:

public Stream<String> collectionToStream(Collection<String> collection) {
return Optional.ofNullable(collection)
.map(Collection::stream)
.orElseGet(Stream::empty);
}
  • Optional.ofNullable(коллекция) создает необязательный объект из переданной коллекции. Пустой необязательный объект создается, если коллекция имеет значение null.
  • map(Collection::stream) извлекает значение, содержащееся в объекте Optional , в качестве аргумента метода карты ( Collection.stream() )
  • orElseGet(Stream::empty) возвращает резервное значение в случае, если необязательный объект пуст, т. е. переданная коллекция имеет значение null .

В результате мы активно защищаем наш код от непреднамеренных исключений нулевого указателя.

4.4. Используйте Stream OfNullable в Java 9

Изучая наш предыдущий троичный пример в разделе 4.1. и учитывая возможность того, что некоторые элементы могут быть нулевыми вместо Collection , в нашем распоряжении есть метод ofNullable в классе Stream .

Мы можем преобразовать приведенный выше образец в:

Stream<String> collectionAsStream(Collection<String> collection) {  
return collection.stream().flatMap(s -> Stream.ofNullable(s));
}

5. Вывод

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

Наконец, мы указали на недостатки использования каждой стратегии там, где это уместно.

Как обычно, полный исходный код, сопровождающий статью, доступен на GitHub .