Поиск по сайту:

Примеры методов Java Stream collect()


Java Stream collect() выполняет изменяемую операцию сокращения элементов потока. Это терминальная операция.

Что такое операция мутабельной редукции?

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

Подпись метода Java Stream collect()

Существует два варианта метода collect() в Java Stream.

  1. R collect (поставщик Supplier, аккумулятор BiConsumer, объединитель BiConsumer)
  2. R collect(Коллектор коллектор)

Коллектор — это интерфейс, предоставляющий оболочку для объектов поставщика, накопителя и объединителя. Второй метод полезен, когда мы используем класс Collectors для реализации встроенной реализации Collector. Три параметра функции collect():

  1. поставщик: функция, которая создает новый изменяемый контейнер результатов. Для параллельного выполнения эту функцию можно вызывать несколько раз, и каждый раз она должна возвращать новое значение.
  2. накопитель – это функция без сохранения состояния, которая должна складывать элемент в контейнер результатов.
  3. combiner — это функция без сохранения состояния, которая принимает два контейнера частичных результатов и объединяет их, что должно быть совместимо с функцией-аккумулятором.

Примеры метода Stream collect()

Давайте рассмотрим несколько примеров метода Stream.collect().

1. Объединение списка строк

Допустим, вы хотите объединить список строк, чтобы создать новую строку. Мы можем использовать функцию Stream collect() для выполнения изменяемой операции сокращения и объединения элементов списка.

List<String> vowels = List.of("a", "e", "i", "o", "u");

// sequential stream - nothing to combine
StringBuilder result = vowels.stream().collect(StringBuilder::new, (x, y) -> x.append(y),
		(a, b) -> a.append(",").append(b));
System.out.println(result.toString());

// parallel stream - combiner is combining partial results
StringBuilder result1 = vowels.parallelStream().collect(StringBuilder::new, (x, y) -> x.append(y),
		(a, b) -> a.append(",").append(b));
System.out.println(result1.toString());

Выход:

aeiou
a,e,i,o,u

  • Функция поставщика возвращает новый объект StringBuilder при каждом вызове.
  • Функция аккумулятора добавляет элемент строки списка к экземпляру StringBuilder.
  • Функция объединителя объединяет экземпляры StringBuilder. Экземпляры объединяются друг с другом с запятой между ними.
  • В первом случае у нас есть последовательный поток элементов. Таким образом, они обрабатываются один за другим, и существует только один экземпляр StringBuilder. Функция объединения не используется. Вот почему на выходе получается \aeiou.
  • Во втором случае у нас есть параллельный поток строк. Таким образом, элементы обрабатываются параллельно, и существует несколько экземпляров StringBuilder, которые объединяются функцией объединения. Следовательно, полученный результат равен \a,e,i,o,u.
  • Если источник потока упорядочен, например Set, то метод collect() может давать разные результаты при каждом вызове.

Если вы хотите объединить список строк, мы можем использовать ссылки на методы, чтобы уменьшить размер кода.

String result2 = vowels.parallelStream()
		.collect(StringBuilder::new, StringBuilder::append, StringBuilder::append)
		.toString();

2. Потоковая передача collect() в список с использованием класса Collectors

Класс Collectors предоставляет множество полезных реализаций интерфейса Collector. Давайте рассмотрим пример, в котором мы будем фильтровать список целых чисел, чтобы выбрать только четные целые числа. Stream filter() является промежуточной операцией и возвращает поток. Итак, мы будем использовать функцию collect() для создания списка из этого потока.

List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6);
		
List<Integer> evenNumbers = numbers.stream().filter(x -> x % 2 == 0).collect(Collectors.toList());
System.out.println(evenNumbers);  // [2, 4, 6]

Collectors.toList() возвращает реализацию Collector, которая накапливает входные элементы в новый список.

3. Потоковая передача collect() в набор

Мы можем использовать Collectors.toSet() для сбора элементов потока в новый набор.

List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6);

Set<Integer> oddNumbers = numbers.parallelStream().filter(x -> x % 2 != 0).collect(Collectors.toSet());
System.out.println(oddNumbers); // [1, 3, 5]

3. Потоковая передача collect() на карту

Мы можем использовать функцию Collectors.toMap() для сбора элементов потока на карту. Этот метод принимает два аргумента для ключа сопоставления и соответствующее значение в Map.

List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6);

Map<Integer, String> mapOddNumbers = numbers.parallelStream().filter(x -> x % 2 != 0)
		.collect(Collectors.toMap(Function.identity(), x -> String.valueOf(x)));
System.out.println(mapOddNumbers); // {1=1, 3=3, 5=5}

4. Пример соединения коллекторов()

Мы можем использовать методы Collectors joining(), чтобы получить Collector, который объединяет элементы CharSequence входного потока в порядке встречи. Мы можем использовать это для объединения потока строк, StringBuffer или StringBuilder.

jshell> String value = Stream.of("a", "b", "c").collect(Collectors.joining());
value ==> "abc"

jshell> String valueCSV = Stream.of("a", "b", "c").collect(Collectors.joining(","));
valueCSV ==> "a,b,c"

jshell> String valueCSVLikeArray = Stream.of("a", "b", "c").collect(Collectors.joining(",", "{", "}"));
valueCSVLikeArray ==> "{a,b,c}"

jshell> String valueObject = Stream.of("1", new StringBuffer("2"), new StringBuilder("3")).collect(Collectors.joining());
valueObject ==> "123"

Выход:

Заключение

Java Stream collect() в основном используется для сбора элементов потока в коллекцию. Это терминальная операция. Он обеспечивает синхронизацию при использовании с параллельным потоком. Класс Collectors предоставляет множество реализаций Collector, чтобы помочь нам.

Рекомендации

  • Документ API Stream collect()
  • Интерфейс коллектора
  • Документ по API коллекторов