T
- the type of input elements to the reduction operationA
- the mutable accumulation type of the reduction operation (often
hidden as an implementation detail)R
- the result type of the reduction operationpublic interface Collector<T,A,R>
Examples of mutable reduction operations include:
accumulating elements into a Collection
; concatenating
strings using a StringBuilder
; computing summary information about
elements such as sum, min, max, or average; computing "pivot table" summaries
such as "maximum valued transaction by seller", etc. The class Collectors
provides implementations of many common mutable reductions.
A Collector
is specified by four functions that work together to
accumulate entries into a mutable result container, and optionally perform
a final transform on the result. They are:
supplier()
)accumulator()
)combiner()
)finisher()
)Collectors also have a set of characteristics, such as
Collector.Characteristics.CONCURRENT
, that provide hints that can be used by a
reduction implementation to provide better performance.
A sequential implementation of a reduction using a collector would create a single result container using the supplier function, and invoke the accumulator function once for each input element. A parallel implementation would partition the input, create a result container for each partition, accumulate the contents of each partition into a subresult for that partition, and then use the combiner function to merge the subresults into a combined result.
To ensure that sequential and parallel executions produce equivalent results, the collector functions must satisfy an identity and an associativity constraints.
The identity constraint says that for any partially accumulated result,
combining it with an empty result container must produce an equivalent
result. That is, for a partially accumulated result a
that is the
result of any series of accumulator and combiner invocations, a
must
be equivalent to combiner.apply(a, supplier.get())
.
The associativity constraint says that splitting the computation must
produce an equivalent result. That is, for any input elements t1
and t2
, the results r1
and r2
in the computation
below must be equivalent:
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
For collectors that do not have the UNORDERED
characteristic,
two accumulated results a1
and a2
are equivalent if
finisher.apply(a1).equals(finisher.apply(a2))
. For unordered
collectors, equivalence is relaxed to allow for non-equality related to
differences in order. (For example, an unordered collector that accumulated
elements to a List
would consider two lists equivalent if they
contained the same elements, ignoring order.)
Libraries that implement reduction based on Collector
, such as
Stream.collect(Collector)
, must adhere to the following constraints:
Collector
needing to implement any additional synchronization.
The reduction implementation must manage that the input is properly
partitioned, that partitions are processed in isolation, and combining
happens only after accumulation is complete.Collector.Characteristics.UNORDERED
characteristics or if the
originating data is unordered.In addition to the predefined implementations in Collectors
, the
static factory methods of(Supplier, BiConsumer, BinaryOperator, Characteristics...)
can be used to construct collectors. For example, you could create a collector
that accumulates widgets into a TreeSet
with:
Collector<Widget, ?, TreeSet<Widget>> intoSet =
Collector.of(TreeSet::new, TreeSet::add,
(left, right) -> { left.addAll(right); return left; });
(This behavior is also implemented by the predefined collector
Collectors.toCollection(Supplier)
).Collector
should produce a
result equivalent to:
R container = collector.supplier().get();
for (T t : data)
collector.accumulator().accept(container, t);
return collector.finisher().apply(container);
However, the library is free to partition the input, perform the reduction on the partitions, and then use the combiner function to combine the partial results to achieve a parallel reduction. (Depending on the specific reduction operation, this may perform better or worse, depending on the relative cost of the accumulator and combiner functions.)
Collectors are designed to be composed; many of the methods
in Collectors
are functions that take a collector and produce
a new collector. For example, given the following collector that computes
the sum of the salaries of a stream of employees:
Collector<Employee, ?, Integer> summingSalaries
= Collectors.summingInt(Employee::getSalary))
If we wanted to create a collector to tabulate the sum of salaries by
department, we could reuse the "sum of salaries" logic using
Collectors.groupingBy(Function, Collector)
:
Collector<Employee, ?, Map<Department, Integer>> summingSalariesByDept
= Collectors.groupingBy(Employee::getDepartment, summingSalaries);
Stream.collect(Collector)
,
Collectors
Modifier and Type | Interface | Description |
---|---|---|
static class |
Collector.Characteristics |
Characteristics indicating properties of a
Collector , which can
be used to optimize reduction implementations. |
Modifier and Type | Method | Description |
---|---|---|
BiConsumer<A,T> |
accumulator() |
A function that folds a value into a mutable result container.
|
Set<Collector.Characteristics> |
characteristics() |
Returns a
Set of Collector.Characteristics indicating
the characteristics of this Collector. |
BinaryOperator<A> |
combiner() |
A function that accepts two partial results and merges them.
|
Function<A,R> |
finisher() |
Perform the final transformation from the intermediate accumulation type
A to the final result type 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) |
Returns a new
Collector described by the given supplier ,
accumulator , combiner , and finisher functions. |
static <T,R> Collector<T,R,R> |
of(Supplier<R> supplier,
BiConsumer<R,T> accumulator,
BinaryOperator<R> combiner,
Collector.Characteristics... characteristics) |
Returns a new
Collector described by the given supplier ,
accumulator , and combiner functions. |
Supplier<A> |
supplier() |
A function that creates and returns a new mutable result container.
|
Supplier<A> supplier()
BiConsumer<A,T> accumulator()
BinaryOperator<A> combiner()
Function<A,R> finisher()
A
to the final result type R
.
If the characteristic IDENTITY_FINISH
is
set, this function may be presumed to be an identity transform with an
unchecked cast from A
to R
.
Set<Collector.Characteristics> characteristics()
Set
of Collector.Characteristics
indicating
the characteristics of this Collector. This set should be immutable.static <T,R> Collector<T,R,R> of(Supplier<R> supplier, BiConsumer<R,T> accumulator, BinaryOperator<R> combiner, Collector.Characteristics... characteristics)
Collector
described by the given supplier
,
accumulator
, and combiner
functions. The resulting
Collector
has the Collector.Characteristics.IDENTITY_FINISH
characteristic.T
- The type of input elements for the new collectorR
- The type of intermediate accumulation result, and final result,
for the new collectorsupplier
- The supplier function for the new collectoraccumulator
- The accumulator function for the new collectorcombiner
- The combiner function for the new collectorcharacteristics
- The collector characteristics for the new
collectorCollector
NullPointerException
- if any argument is nullstatic <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
described by the given supplier
,
accumulator
, combiner
, and finisher
functions.T
- The type of input elements for the new collectorA
- The intermediate accumulation type of the new collectorR
- The final result type of the new collectorsupplier
- The supplier function for the new collectoraccumulator
- The accumulator function for the new collectorcombiner
- The combiner function for the new collectorfinisher
- The finisher function for the new collectorcharacteristics
- The collector characteristics for the new
collectorCollector
NullPointerException
- if any argument is null Submit a bug or feature
For further API reference and developer documentation, see Java SE Documentation. That documentation contains more detailed, developer-targeted descriptions, with conceptual overviews, definitions of terms, workarounds, and working code examples.
Copyright © 1993, 2017, Oracle and/or its affiliates. 500 Oracle Parkway
Redwood Shores, CA 94065 USA. All rights reserved.
DRAFT 9-internal+0-adhoc.mlchung.jdk9-jdeps