Почему я получаю Stream <Object>, когда я вызываю stream () после collect ()? - PullRequest
0 голосов
/ 27 сентября 2018

Рассмотрим следующий пример, который не скомпилирован:

List<Integer> list = Arrays.asList(1, 2, -3, 8);

        list.stream()
                .filter(x -> x > 0)
                .collect(ArrayList::new, ArrayList::add, ArrayList::addAll)
                .stream() // Stream<Object>
                .map(x -> x * 2)
                .forEach(System.out::println);

Если я заменю

.collect(ArrayList::new, ArrayList::add, ArrayList::addAll)

на

.collect(Collectors.toList())

Код будет скомпилирован.Поэтому вопрос заключается в том, как мне написать collect() с поставщиком и аккумулятором (мне это нужно), чтобы иметь возможность вызвать stream() после него?

1 Ответ

0 голосов
/ 27 сентября 2018

Похоже, что вы сделали необработанную ссылку на метод для конструктора ArrayList с ArrayList::new.

Аргумент типа не был выведен с помощью:

.collect(ArrayList::new, ArrayList::add, ArrayList::addAll)

The Перегрузка с 3 аргументами collect ожидает 3 аргумента, первый из которых - Supplier<R>.На данный момент нет никакой связи между аргументом типа collect метода R и T, который здесь Integer.Единственный способ сделать вывод об этом - использовать второй аргумент, BiConsumer<R, ? super T>.Здесь у вас есть ArrayList::add, что не дает компилятору возможности сделать вывод R.

Вы должны указать, что R в первом аргументе, Поставщик.Вы можете предоставить явные аргументы типа классу для создания на основе ссылки на метод.

.collect(ArrayList<Integer>::new, ArrayList::add, ArrayList::addAll)

Компилируется, и вывод такой, как ожидается:

2
4
16

Когда вы используете Collectors.toList(), вы предоставляете только один аргумент.

public static <T> Collector<T,?,List<T>> toList()

Здесь есть только один аргумент типа T, поэтому компиляторможет правильно сделать вывод, что T равен Integer, поэтому создается List<Integer>, что позволяет скомпилировать код.Аргументы типа для Collector возвращают привязку T к List<T>, что позволяет компилятору выполнять вывод типа.

Обратите внимание, что это необходимо только в первую очередь, поскольку нет целевого типа дляпомочь с выводом типа;вы продолжаете манипулирование потоком и просто вызываете System.out.println в конце, что может занять Object.

Если бы у вас был этот код:

List<Integer> modified = list.stream()
            .filter(x -> x > 0)
            .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);

Тогда вывод целевого типа будетпредоставили Integer для аргумента типа ArrayList::new.Это также компилируется.

...