Как лучше всего создать поток Java 8 из объекта с нулевым значением?

Каков наилучший/идиоматический способ выполнения нулевой проверки перед получением потока?

У меня есть метод, который получает List который может быть нулевым. Поэтому я не могу просто вызвать .stream() для переданного значения. Есть ли какой-то статический помощник, который дал бы мне пустой поток, если значение равно null?

Ответы

Ответ 1

Я согласен со Стюартом Марксом, что list == null? Stream.empty(): list.stream() list == null? Stream.empty(): list.stream() - это правильный способ сделать это (см. Его ответ) или, по крайней мере, правильный способ сделать это до Java 9 (см. Редактирование ниже), но я оставлю этот ответ до демонстрации использования Дополнительного API.

<T> Stream<T> getStream(List<T> list) {
    return Optional.ofNullable(list).map(List::stream).orElseGet(Stream::empty);
}

Редактировать: Java 9 добавил статический фабричный метод Stream.<T>ofNullable(T), который возвращает пустой поток с null аргументом, в противном случае поток с аргументом является единственным элементом. Если аргумент является коллекцией, мы можем затем использовать flatMap чтобы превратить его в поток.

<T> Stream<T> fromNullableCollection(Collection<? extends T> collection) {
    return Stream.ofNullable(collection).flatMap(Collection::stream);
}

Это не злоупотребляет дополнительным API, как обсуждалось Стюартом Марксом, и, в отличие от решения с троичными операторами, нет никакой возможности для исключения нулевого указателя (например, если вы не обращали внимания и испортили порядок операндов). Он также работает с подстановочным знаком с верхним ограничением без использования SuppressWarnings("unchecked") благодаря сигнатуре flatMap, так что вы можете получить Stream<T> из коллекции элементов любого подтипа T

Ответ 2

Самое лучшее, что я могу думать о том, чтобы использовать Optional с orElseGet методом.

return Optional.ofNullable(userList)
                .orElseGet(Collections::emptyList)
                .stream()
                .map(user -> user.getName())
                .collect(toList());

Обновлено с помощью @Misha, чтобы использовать Collections::emptyList ArrayList::new

Ответ 3

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

Позвольте мне предложить следующую прозаическую технику:

static <T> Stream<T> nullableListToStream(List<T> list) {
    return list == null ? Stream.empty() : list.stream();
}

Я думаю, что тернарный оператор в наши дни несколько декален, но я думаю, что это самое простое и эффективное решение.

Если бы я писал это по-настоящему (то есть для реальной библиотеки, а не только для образца кода в Stack Overflow), я бы поставил подстановочные знаки, чтобы тип возвращаемого потока мог отличаться от типа List. О, и это может быть коллекция, так как там, где определяется метод stream():

@SuppressWarnings("unchecked")
static <T> Stream<T> nullableCollectionToStream(Collection<? extends T> coll) {
    return coll == null ? Stream.empty() : (Stream<T>)coll.stream();
}

(Подавление предупреждений необходимо из-за того, что из Stream<? extends T> в Stream<T> это безопасно, но компилятор этого не знает).

Ответ 4

apache commons-collections4:

CollectionUtils.emptyIfNull(list).stream()

Ответ 5

Лично я считаю null устаревшим и использовать Необязательный, когда это возможно, несмотря на (незначительные) накладные расходы. Поэтому я использую интерфейс от Stuart Marks с реализацией на основе gdejohn, т.е.

@SuppressWarnings("unchecked")
static <T> Stream<T> nullableCollectionToStream(Collection<? extends T> coll)
{
    return (Stream<T>) Optional.ofNullable(coll)
                           .map(Collection::stream)
                           .orElseGet(Stream::empty);
}