package java.util.stream;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Objects;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function .BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* A <a href="package-summary.html#Reduction">Variable reduction (reduction/convergence) Operation</a>
* Accumulates elements into a mutable result container,
* optionally converts the accumulated result to a final representation after all input elements have been processed.
* Reduction operations can be performed serially or in parallel.
*
* <p> Examples of variable reduction operations include:
* accumulating elements into a {@code Collection},
* concatenating strings using {@code StringBuilder},
* computing elements such as sum, min, max, or average aggregated information,
* Calculate totals for "PivotTables" such as "Seller Max Transactions", etc.
* This class {@link Collectors} provides implementations of many common reduction operations.
*
* <p>A {@code 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: <ul>
* <li> Create a new result container ({@link #supplier()})</li>
* <li>merge a new data element into the result container ({@link #accumulator()})</li>
* <li>Merge the two result containers into one ({@link #combiner()})</li>
* <li>Perform an optional final transformation on the container ({@link #finisher()})</li> li>
* </ul>
*
* <p>Collectors have a series of characteristics, such as
* {@link Characteristics#CONCURRENT},
* <p>A serial implementation of a reduction operation using a collector would use the supplier functional interface
* to create a single result container and call the accumulator function once for each input element.
* The parallel implementation will partition the input, create a result container for each partition,
* accumulate the contents of each partition into the subresults for that partition (subresult), then use the combiner (merge)
* function to combine each subresult for the final result.
*
* <p>To ensure that serial execution and parallel execution produce equivalent results, the collector function must satisfy
*<em>identity</em> and <a href="package-summary.html#Associativity">associativity</em> a> Constraint
*
* The <p>identity constraint states that for any partially accumulated result, combining it with an empty result container,
* must produce a result equal to the final result.
* That is, for a partially accumulated result {@code a}, the result of any series of accumulator and
* combiner calls, {@code a} must be equal to {@code combiner.apply(a, supplier.get() )}.
*
* <p> associativity means that the division computation must produce equivalent results.
* That is, for any input elements {@code t1} and {@code t2}, the following
* In the calculation, the results {@code t1} and {@code t2} must be equal.
* <pre>{@code
* A a1 = supplier.get();
* accumulator.accept(a1, t1);
* accumulator.accept(a1, t2);
* R r1 = finisher.apply(a1); // Result is not split
*
* 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 split
* } </pre>
*
* <p>For collectors without the {@code UNORDERED} feature,
* two accumulated results{@ code a1} and {@code a2} are equivalent to er.apply(a1).equals(finisher.apply(a2))}.
* For unordered collectors, equivalence is relaxed, allowing equality in different order.
* (eg: an unordered collector accumulates elements into {@code List}, if they contain the same elements, ignoring the order
* will treat them as the same list).
*
* <p>The library implements the reduction operation based on {@code Collector}, for example: {@link Stream#collect(Collector)},
* must adhere to the following constraints:
* <ul>
* <li>Passed to the accumulator function The first parameter, the parameter passed to the combiner function,
* and the parameter passed to the finisher function must be
the result of the previous call to supplier, accumulator, combiner *.
*
* <li>The implementation SHOULD NOT do anything with the * results of any supplier, accumulator, and combiner functions
, except pass them again to the accumulator, combiner, or finisher
* functions, or return them to the caller of the reduction operation .
*
* <li>If the result is passed to a combiner or finisher function,
* and the same object is not returned from this function, it is not used again.
*
* <li>Once a result is passed to the combiner or finisher functions,
* It will never be passed to the accumulator function again.
*
*
* <li>For non-concurrent collectors,
any results * returned from a supplier, accumulator, or combiner function must be serial thread bound.
* This allows the collection to execute concurrently without the need for {@code Collector} to implement
* any additional synchronization.
* Reduction implementations must manage input into its correct partitions, partitions are processed independently,
* and merged only after accumulation.
*
*
* <li>For concurrent collectors, implementation MAY be free (but not required) concurrent implementation reduction.
* Concurrent reduction is calling the accumulator function concurrently in multiple threads, using the same
* concurrently modifiable result container, rather than isolating this result during accumulation.
* Concurrent reduction should only be used if the collector has the {@link Characteristics#UNORDERED} characteristic or
* if the original data is unordered.
* </ul>
*
* <p>Except in {@link Collectors} Defined outside the implementation, static factory methods
* {@link #of(Supplier, BiConsumer, BinaryOperator, Characteristics...)} can also
* be used to build collectors. For example, you can create a collector to accumulate widgets into {@code TreeSet}:
*
* <pre>{@code
* Collector<Widget, ?, TreeSet<Widget>> intoSet =
* Collector.of(TreeSet::new, TreeSet ::add,
* (left, right) -> { left.addAll(right); return left; });
* }</pre>
*
* (This behavior is also implemented by the predefined collector
* {@link Collectors# toCollection(Supplier)}).
*
* @apiNote
* Performing a reduction operation with {@code Collector} should yield the equivalent of:
* <pre>{@code
* R container = collector.supplier().get( );
* for (T t : data)
* collector.accumulator().accept(container, t);
* return collector.finisher().apply(container);
* }</pre>
*
* <p>However, the library is free to divide the input on partitions Perform a reduction operation,
* then use the combiner function to combine partial results for parallel reduction.
* (may perform better or worse depending on the specific reduction operation, depending on
* the associated accumulator and combiner function overhead)
*
* <p>Collectors are designed to be <em>composable</em> ;Many of the methods in {@link Collectors}
* take a new collector and generate a new one.
* For example, given the following collector, calculate the total salary of employees.
*
* <pre>{@code
* Collector<Employee, ?, Integer> summingSalaries
* = Collectors.summingInt(Employee::getSalary))
* }</pre>
*
* If we want to create a collector to count by department The sum of wages, we can use
* {@link Collectors#groupingBy(Function, Collector)}来重用“薪水总和”的逻辑。
*
* <pre>{@code
* Collector<Employee, ?, Map<Department, Integer>> summingSalariesByDept
* = Collectors.groupingBy(Employee::getDepartment, summingSalaries);
* }</pre>
*
* @see Stream#collect(Collector)
* @see Collectors
*
* @param <T> the type of input elements to the reduction operation
* @param <A> the mutable accumulation type of the reduction operation (often
* hidden as an implementation detail)
* @param <R> the result type of the reduction operation
* @since 1.8
*/
public interface Collector<T, A, R> {
/**
* Function that creates and returns a new mutable result container.
* @return a function which returns a new, mutable result container
*/
Supplier<A> supplier();
/**
* A function which folds a value into a mutable result
*
* @return a function which folds a value into a mutable result container
*/
BiConsumer<A, T> accumulator();
/**
* A function that takes two partial results and combines them.
The * combiner function can stack state from one argument to another and return it,
* or return a new result container.
*
* @return a function which combines two partial results into a combined
* result
*/
BinaryOperator<A> combiner();
/**
* Perform a conversion from intermediate result type {@code A} to final result type {@code R}.
*
* <p>If the characteristic {@code IDENTITY_TRANSFORM} is
* set, this function may be presumed to be an identity transform with an
* unchecked cast from {@code A} to {@code R}.
*
* @return a function which transforms the intermediate result to the final
* result
*/
Function<A, R> finisher();
/**
* Returns a {@code Set} of {@code Collector.Characteristics}, indicating
* the characteristics of the collector. This collection should be immutable.
*
* @return an immutable set of collector characteristics
*/
Set<Characteristics> characteristics();
/** * Returns the new collector described
by the given {@code supplier}, {@code accumulator}, and {@code combiner} functions *.
This result {@code Collector} has {@code Collector.Characteristics.IDENTITY_FINISH}
* characteristics
*
* @param supplier new collector's supplier function
* @param accumulator new collector's accumulator function
* @param combiner new collector's combiner function
* @param characteristics The characteristics of the new collector
*
* @param <T> The type of the input element of the new collector
* @param <R> The type of the intermediate calculation result and the final result of the new collector.
* @throws NullPointerException if any argument is null
* @return the new {@code Collector}
*/
public static<T, R> Collector<T, R, R> of(Supplier<R> supplier,
BiConsumer<R, T> accumulator,
BinaryOperator<R> combiner,
Characteristics... characteristics) {
Objects.requireNonNull(supplier);
Objects.requireNonNull(accumulator);
Objects.requireNonNull(combiner);
Objects.requireNonNull(characteristics);
Set<Characteristics> cs = (characteristics.length == 0)
? Collectors.CH_ID
: Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH,
characteristics));
return new Collectors.CollectorImpl<>(supplier, accumulator, combiner, cs);
}
/**
* Returns an array created by the given {@code supplier},
* {@code accumulator}, {@code combiner} , and
the collector described by the {@code finisher} function *.
*
* @param supplier the supplier function of the
new collector * @param accumulator the accumulator function of the
new collector * @param combiner the combiner function of the
new collector * @param finisher the finisher function of the
new collector * @param characteristics the characteristics of the new collector feature.
*
* @param <T> The type of input elements for the new collector
* @param <A> The intermediate accumulation type of the new collector
* @param <R> The final result type of the new collector
* @throws NullPointerException if any argument is null
* @return the new {@code Collector}
*/
public static<T, A, R> Collector<T, A, R> of(Supplier<A> supplier,
BiConsumer<A, T> accumulator,
BinaryOperator<A> combiner,
Function<A, R> finisher,
Characteristics... characteristics) {
Objects.requireNonNull(supplier);
Objects.requireNonNull(accumulator);
Objects.requireNonNull(combiner);
Objects.requireNonNull(finisher);
Objects.requireNonNull(characteristics);
Set<Characteristics> cs = Collectors.CH_NOID;
if (characteristics.length > 0) {
cs = EnumSet .noneOf(Characteristics.class);
Collections.addAll(cs, characteristics);
cs = Collections.unmodifiableSet(cs);
}
return new Collectors.CollectorImpl<>(supplier, accumulator, combiner, finisher, cs);
}
/**
* Characteristics indicate properties of {@code Collector} that
* can be used to optimize reduction implementations.
*/
enum Characteristics {
/**
* Indicates that this collector is <em>concurrent</em>, meaning that
* the result container can support the accumulator function being
* called concurrently with the same result container from multiple
* threads.
*
* <p>If a {@code CONCURRENT} collector is not also {@code UNORDERED},
* then it should only be evaluated concurrently if applied to an
* unordered data source.
*/
CONCURRENT,
/**
* Indicates that the collection operation does not commit to preserving
* the encounter order of input elements. (This might be true if the
* result container has no intrinsic order, such as a {@link Set}.)
*/
UNORDERED,
/**
* Indicates that the finisher function is the identity function and
* can be elided. If set, it must be the case that an unchecked cast
* from A to R will succeed.
*/
IDENTITY_FINISH
}
}
Collector.java official document translation
Guess you like
Origin http://10.200.1.11:23101/article/api/json?id=326632380&siteId=291194637
Recommended
Ranking