Может ли Java Stream.collect() возвращать null?

JavaDoc для Stream.collect() говорит, что он возвращает the result of the reduction. Это не говорит мне, если такой код может вернуть значение null для filterList:

List<String> filteredList = inputList.stream().
filter(c -> c.getSomeBoolean()).
flatMap(c -> {
  List<String> l = new ArrayList<String>();
  l.add(c.getSomething());
  l.add(c.getSomethingElse());
  return l.stream();
}).
filter(s -> StringUtils.isNotBlank(s)).
collect(Collectors.toList());

Я ожидал бы, что если он сможет вернуть значение null, то он будет возвращать необязательный, но он не говорит об этом.

Документирован ли он где-либо, может ли Stream.collect() возвращать значение null?

Ответ 1

Collector.toList() вернет вам пустой список.

Вот реализация:

public static <T>
Collector<T, ?, List<T>> toList() {
    return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
                               (left, right) -> { left.addAll(right); return left; },
                               CH_ID);
}

Как вы можете видеть, ArrayList::new используется в качестве контейнера для ваших предметов.


Изменить

Я вижу здесь много сомнений, поэтому я прочитал JavaDoc и поделился с вами:

Из JavaDoc для Collector:

открытый интерфейс Collector

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

Коллектор определяется четырьмя функциями, которые работают вместе, чтобы накапливать записи в изменяемый контейнер результатов и, при необходимости, выполнить окончательное преобразование результата. Они:

  • создание нового контейнера результатов (поставщик())

  • встраивание нового элемента данных в контейнер результатов (аккумулятор())

  • объединение двух контейнеров результатов в один (combiner())
  • выполнение необязательного финального преобразования для контейнера (finisher())

И

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

Так что, пока вы не делаете странные вещи, такие как функция комбинированного возврата null, Collector всегда возвращает по крайней мере mutable container, используя предоставленную вами функцию supplier.

И я думаю, что это очень нелогично, если реализация когда-нибудь вернет контейнер null.

Ответ 2

Это зависит не от Stream.collect, а от отдельного Collector. Collectors.toList() вернет пустое ArrayList.

Тем не менее, нет причины, по которой кто-то не мог бы использовать странный Collector для возврата нуля при определенных обстоятельствах:

.collect(
    Collector.of(
        ArrayList::new,
        ArrayList::add,
        (a, b) -> {
            a.addAll(b);
            return a;
        },
        a -> a.isEmpty() ? null : a  // finisher replaces empty list with null
    )
);

Итак, Collector - это то, что вам нужно запомнить, чтобы проверить. Я полагаю, что все Collectors доступные из коробки вернут пустые коллекции, как и следовало ожидать.

Ответ 3

Я думаю, что эта часть документации говорит, что она не может быть нулевой:

Возвращает коллектор, который накапливает входные элементы в п ш списка.

Основные моменты, добавленные мной. Я думаю, что этот новый список означает что-то, что не является нулевым.

Я начал проверять ReferencePipeline.collect() чтобы проверить, действительно ли это для реальной реализации. К сожалению, это была бесполезная попытка. Здесь очень много случаев, например, параллельно? это после forEach? и т.п.

Ответ 4

Это зависит от коллектива. Тот, который вы используете (Collectors.toList()), возвращает пустой список.