/* * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.util.stream; import java.util.Collections; import java.util.EnumSet; 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 reduction operation that * folds input elements into a mutable result container, optionally transforming * the accumulated result into a final representation after all input elements * have been processed. * *

Examples of mutable reduction operations include: * accumulating elements into a {@code Collection}; concatenating * strings using a {@code 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. Reduction operations * can be performed either sequentially or in parallel. * *

The following are examples of using the predefined {@code Collector} * implementations in {@link Collectors} with the {@code Stream} API to perform * mutable reduction tasks: *

{@code
 *     // Accumulate names into a List
 *     List list = people.stream().map(Person::getName).collect(Collectors.toList());
 *
 *     // Accumulate names into a TreeSet
 *     Set list = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new));
 *
 *     // Convert elements to strings and concatenate them, separated by commas
 *     String joined = things.stream()
 *                           .map(Object::toString)
 *                           .collect(Collectors.joining(", "));
 *
 *     // Find highest-paid employee
 *     Employee highestPaid = employees.stream()
 *                                     .collect(Collectors.maxBy(Comparators.comparing(Employee::getSalary)))
 *                                     .get();
 *
 *     // Group employees by department
 *     Map> byDept
 *         = employees.stream()
 *                    .collect(Collectors.groupingBy(Employee::getDepartment));
 *
 *     // Find highest-paid employee by department
 *     Map> highestPaidByDept
 *         = employees.stream()
 *                    .collect(Collectors.groupingBy(Employee::getDepartment,
 *                                                   Collectors.maxBy(Comparators.comparing(Employee::getSalary))));
 *
 *     // Partition students into passing and failing
 *     Map> passingFailing =
 *         students.stream()
 *                 .collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD));
 *
 * }
* *

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: creation of a new result container, * incorporating a new data element into a result container, combining two * result containers into one, and performing a final transform on the container. * The combiner function is used during parallel operations, where * subsets of the input are accumulated into separate result * containers, and then the subresults merged into a combined result. The * combiner function may merge one set of subresults into the other and return * that, or it may return a new object to describe the combined results. * *

Collectors also have a set of characteristics, such as * {@link Characteristics#CONCURRENT}. These characteristics provide * hints that can be used by a reduction implementation to provide better * performance. * *

Libraries that implement reduction based on {@code Collector}, such as * {@link Stream#collect(Collector)}, must adhere to the following constraints: *

* * @apiNote * Performing a reduction operation with a {@code Collector} should produce a * result equivalent to: *
{@code
 *     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. * *

An example of an operation that can be easily modeled by {@code Collector} * is accumulating elements into a {@code TreeSet}. In this case, the {@code * resultSupplier()} function is {@code () -> new Treeset()}, the * {@code accumulator} function is * {@code (set, element) -> set.add(element) }, and the combiner * function is {@code (left, right) -> { left.addAll(right); return left; }}. * (This behavior is implemented by * {@code Collectors.toCollection(TreeSet::new)}). * * TODO Associativity and commutativity * * @see Stream#collect(Collector) * @see Collectors * * @param the type of input elements to the reduction operation * @param the mutable accumulation type of the reduction operation (often * hidden as an implementation detail) * @param the result type of the reduction operation * @since 1.8 */ public interface Collector { /** * A function that creates and returns a new mutable result container. * * @return a function which returns a new, mutable result container */ Supplier supplier(); /** * A function that folds a new value into a mutable result container. * * @return a function which folds a new value into a mutable result container */ BiConsumer accumulator(); /** * A function that accepts two partial results and merges them. The * combiner function may fold state from one argument into the other and * return that, or may return a new result object. * * @return a function which combines two partial results into a cumulative * result */ BinaryOperator combiner(); /** * Perform the final transformation from the intermediate accumulation type * {@code A} to the final result representation {@code R}. * *

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 finisher(); /** * Returns a {@code Set} of {@code Collector.Characteristics} indicating * the characteristics of this Collector. This set should be immutable. * * @return an immutable set of collector characteristics */ Set characteristics(); /** * Returns a new {@code Collector} described by the given {@code supplier}, * {@code accumulator}, and {@code combiner} functions. The resulting * {@code Collector} has the {@code Collector.Characteristics.IDENTITY_FINISH} * characteristic. * * @param supplier The supplier function for the new collector * @param accumulator The accumulator function for the new collector * @param combiner The combiner function for the new collector * @param characteristics The collector characteristics for the new * collector * @param The type of input elements for the new collector * @param The type of intermediate accumulation result, and final result, * for the new collector * @return the new {@code Collector} */ public static Collector of(Supplier supplier, BiConsumer accumulator, BinaryOperator combiner, Characteristics... characteristics) { Set 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 a new {@code Collector} described by the given {@code supplier}, * {@code accumulator}, {@code combiner}, and {@code finisher} functions. * * @param supplier The supplier function for the new collector * @param accumulator The accumulator function for the new collector * @param combiner The combiner function for the new collector * @param finisher The finisher function for the new collector * @param characteristics The collector characteristics for the new * collector * @param The type of input elements for the new collector * @param The intermediate accumulation type of the new collector * @param The final result type of the new collector * @return the new {@code Collector} */ public static Collector of(Supplier supplier, BiConsumer accumulator, BinaryOperator combiner, Function finisher, Characteristics... characteristics) { Set 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 indicating properties of a {@code Collector}, which can * be used to optimize reduction implementations. */ enum Characteristics { /** * Indicates that this collector is concurrent, meaning that * the result container can support the accumulator function being * called concurrently with the same result container from multiple * threads. * *

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 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 } }