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 .