Spec-Zone.ru › OpenJDK 17

Интерфейс Collector<T,A,R>

Параметры типа:
T - тип входных элементов для операции редукции
A - мутабельный тип накопления для операции редукции (часто скрывается как реализационная деталь)
R - тип результата операции редукции
public interface Collector<T,A,R>
Операция мутабельной редукции, которая накапливает входные элементы в контейнер мутабельного результата, необязательно преобразуя накопленный результат в окончательное представление после обработки всех входных элементов. Операции редукции могут выполняться последовательно или параллельно.

Примеры мутабельных операций редукции включают: накопление элементов в Collection; конкатенацию строк с использованием StringBuilder; вычисление сводной информации об элементах, такой как сумма, минимум, максимум или среднее значение; вычисление сводных таблиц, таких как «транзакция с максимальной стоимостью по продавцу» и т. д. Класс Collectors предоставляет реализации многих общих мутабельных редукций.

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

  • создание нового контейнера результата (supplier())
  • включение нового элемента данных в контейнер результата (accumulator())
  • объединение двух контейнеров результата в один (combiner())
  • выполнение необязательного конечного преобразования контейнера (finisher())

Коллекторы также обладают набором характеристик, таких как Collector.Characteristics.CONCURRENT, которые предоставляют подсказки, которые могут использоваться реализацией редукции для повышения производительности.

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

Для обеспечения эквивалентности последовательных и параллельных выполнений функции коллектора должны удовлетворять ограничениям тождества и ассоциативности.

Ограничение тождества гласит, что для любого частично накопленного результата объединение его с пустым контейнером результата должно давать эквивалентный результат. То есть, для частично накопленного результата a, который является результатом любой последовательности вызовов накопителя и объединителя, a должен быть эквивалентен combiner.apply(a, supplier.get()).

Ограничение ассоциативности гласит, что разделение вычисления должно давать эквивалентный результат. То есть, для любых входных элементов t1 и t2, результаты r1 и r2 в вычислении ниже должны быть эквивалентны:


     A a1 = supplier.get();
     accumulator.accept(a1, t1);
     accumulator.accept(a1, t2);
     R r1 = finisher.apply(a1);  // result without splitting

     A a2 = supplier.get();
     accumulator.accept(a2, t1);
     A a3 = supplier.get();
     accumulator.accept(a3, t2);
     R r2 = finisher.apply(combiner.apply(a2, a3));  // result with splitting
  

Для коллекторов, у которых нет характеристики UNORDERED, два накопленных результата a1 и a2 эквивалентны, если finisher.apply(a1).equals(finisher.apply(a2)). Для неупорядоченных коллекторов эквивалентность ослаблена, чтобы разрешить неравенство, связанное с различиями в порядке. (Например, неупорядоченный коллектор, который накапливал элементы в List , посчитал бы два списка эквивалентными, если бы они содержали одни и те же элементы, игнорируя порядок.)

Библиотеки, которые реализуют редукцию на основе Collector, такие как Stream.collect(Collector), должны придерживаться следующих ограничений:

  • Первый аргумент, передаваемый функции накопителя, оба аргумента, передаваемые функции объединения, и аргумент, передаваемый функции завершения, должны быть результатом предыдущего вызова функций поставщика результата, накопителя или объединителя.
  • Реализация не должна делать ничего с результатом любой из функций поставщика, накопителя или объединителя, кроме как передавать их снова функциям накопителя, объединителя или завершения, или возвращать их вызывающей стороне операции редукции.
  • Если результат передаётся функции объединения или завершения, и тот же объект не возвращается из этой функции, он больше никогда не используется.
  • После того как результат передаётся функции объединения или завершения, он больше никогда не передаётся функции накопителя.
  • Для неконкурентных коллекторов любой результат, возвращаемый функциями поставщика результата, накопителя или объединителя, должен быть сериализовано ограничен потоком. Это позволяет собирать данные параллельно, без необходимости, чтобы Collector реализовывал дополнительную синхронизацию. Реализация редукции должна контролировать, чтобы входные данные были правильно разделены, что разделы обрабатывались изолированно, а объединение происходило только после завершения накопления.
  • Для конкурентных коллекторов реализация свободна (но не обязана) реализовывать редукцию параллельно. Параллельная редукция – это та, где функция накопителя вызывается параллельно из нескольких потоков, используя тот же изменяемый в конкурентном режиме контейнер результата, а не сохраняя результат изолированным во время накопления. Параллельная редукция должна применяться только в том случае, если у коллектора есть характеристика Collector.Characteristics.UNORDERED или если исходные данные неупорядочены.

Помимо предопределённых реализаций в Collectors, статические фабричные методы of(Supplier, BiConsumer, BinaryOperator, Characteristics...) могут быть использованы для построения коллекторов. Например, вы могли бы создать коллектор, который накапливает виджеты в TreeSet следующим образом:


     Collector<Widget, ?, TreeSet<Widget>> intoSet =
         Collector.of(TreeSet::new, TreeSet::add,
                      (left, right) -> { left.addAll(right); return left; });
 
(Это поведение также реализует предопределённый коллектор Collectors.toCollection(Supplier)).
Примечание API:
Выполнение операции редукции с помощью Collector должно давать результат, эквивалентный:

     A container = collector.supplier().get();
     for (T t : data)
         collector.accumulator().accept(container, t);
     return collector.finisher().apply(container);
 

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

Коллекторы предназначены для композиции; многие методы в Collectors являются функциями, которые принимают коллектор и создают новый коллектор. Например, дан следующий коллектор, который вычисляет сумму зарплат потока сотрудников:


     Collector<Employee, ?, Integer> summingSalaries
         = Collectors.summingInt(Employee::getSalary))
 
Если мы захотели создать коллектор для подсчёта суммы зарплат по отделу, мы могли бы переиспользовать логику "суммы зарплат" с помощью Collectors.groupingBy(Function, Collector):

     Collector<Employee, ?, Map<Department, Integer>> summingSalariesByDept
         = Collectors.groupingBy(Employee::getDepartment, summingSalaries);
 
С:
1.8
См. также:
  • Stream.collect(Collector)
  • Collectors

Краткое описание вложенных классов

Модификатор и тип Интерфейс Описание
static enum  Collector.Characteristics
Характеристики, указывающие свойства Collector, которые могут быть использованы для оптимизации реализаций редукции.

Краткое описание методов

Модификатор и тип Метод Описание
BiConsumer<A,T> accumulator()
Функция, которая складывает значение в контейнер мутабельного результата.
Set<Collector.Characteristics> characteristics()
Возвращает Set из Collector.Characteristics, указывающих характеристики этого коллектора.
BinaryOperator<A> combiner()
Функция, которая принимает два частичных результата и объединяет их.
Function<A,R> finisher()
Выполнить конечное преобразование от промежуточного типа накопления A к конечному типу результата R.
static <T, A, R> Collector<T,A,R> of(Supplier<A> supplier, BiConsumer<A,T> accumulator, BinaryOperator<A> combiner, Function<A,R> finisher, Collector.Characteristics... characteristics)
Возвращает новый Collector , описанный заданными функциями supplier, accumulator, combiner и finisher.
static <T, R> Collector<T,R,R> of(Supplier<R> supplier, BiConsumer<R,T> accumulator, BinaryOperator<R> combiner, Collector.Characteristics... characteristics)
Возвращает новый Collector , описанный заданными функциями supplier, accumulator и combiner.
Supplier<A> supplier()
Функция, которая создаёт и возвращает новый мутабельный контейнер результата.

Подробное описание методов

supplier

Supplier<A> supplier()
Функция, которая создаёт и возвращает новый контейнер для результатов.
Возвращает:
функцию, возвращающую новый, изменяемый контейнер результатов

accumulator

BiConsumer<A,T> accumulator()
Функция, которая складывает значение в изменяемый контейнер результатов.
Возвращает:
функцию, складывающую значение в изменяемый контейнер результатов

combiner

BinaryOperator<A> combiner()
Функция, принимающая два промежуточных результата и объединяющая их. Функция combiner может сложить состояние из одного аргумента в другой и вернуть это, или может вернуть новый контейнер результатов.
Возвращает:
функцию, объединяющую два промежуточных результата в объединённый результат

finisher

Function<A,R> finisher()
Выполняет окончательное преобразование из промежуточного типа накопления A в конечный тип результата R.

Если характерная черта IDENTITY_FINISH установлена, эта функция может считаться преобразованием тождества с не проверяемым приведением типов от A к R.

Возвращает:
функцию, преобразующую промежуточный результат в конечный результат

characteristics

Set<Collector.Characteristics> characteristics()
Возвращает Set из Collector.Characteristics , указывающую характеристики этого Collector. Этот набор должен быть неизменяемым.
Возвращает:
неизменяемый набор характеристик коллектора

of

static <T, R> Collector<T,R,R> of(Supplier<R> supplier, BiConsumer<R,T> accumulator, BinaryOperator<R> combiner, Collector.Characteristics... characteristics)
Возвращает новый Collector , описанный заданными функциями supplier, accumulator и combiner. Результирующий Collector имеет характеристику Collector.Characteristics.IDENTITY_FINISH.
Параметры типа:
T - Тип входных элементов для нового коллектора
R - Тип промежуточного результата накопления и конечного результата для нового коллектора
Параметры:
supplier - Функция поставщика для нового коллектора
accumulator - Функция накопления для нового коллектора
combiner - Функция комбинирования для нового коллектора
characteristics - Характеристики коллектора для нового коллектора
Возвращает:
новый Collector
Исключения:
NullPointerException - если какой-либо аргумент равен null

of

static <T, A, R> Collector<T,A,R> of(Supplier<A> supplier, BiConsumer<A,T> accumulator, BinaryOperator<A> combiner, Function<A,R> finisher, Collector.Characteristics... characteristics)
Возвращает новый Collector , описанный заданными функциями supplier, accumulator, combiner и finisher.
Параметры типа:
T - Тип входных элементов для нового коллектора
A - Промежуточный тип накопления нового коллектора
R - Конечный тип результата нового коллектора
Параметры:
supplier - Функция поставщика для нового коллектора
accumulator - Функция накопления для нового коллектора
combiner - Функция комбинирования для нового коллектора
finisher - Функция завершения для нового коллектора
characteristics - Характеристики коллектора для нового коллектора
Возвращает:
новый Collector
Исключения:
NullPointerException - если какой-либо аргумент равен null

© 1993, 2021, Oracle and/or its affiliates. All rights reserved.
Documentation extracted from Debian's OpenJDK Development Kit package.
Licensed under the GNU General Public License, version 2, with the Classpath Exception.
Various third party code in OpenJDK is licensed under different licenses (see Debian package).
Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.
https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/stream/Collector.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API