# HG changeset patch # User briangoetz # Date 1372451214 14400 # Node ID e5901820c3c16bfb5d5125062652b4a7b72cd3d5 # Parent c360667a0da29943135bf3f9a57c6a406f57778e 8015318: Extend Collector with 'finish' operation Reviewed-by: mduigou Contributed-by: brian.goetz@oracle.com diff -r c360667a0da2 -r e5901820c3c1 jdk/src/share/classes/java/util/DoubleSummaryStatistics.java --- a/jdk/src/share/classes/java/util/DoubleSummaryStatistics.java Tue Aug 06 16:01:39 2013 -0700 +++ b/jdk/src/share/classes/java/util/DoubleSummaryStatistics.java Fri Jun 28 16:26:54 2013 -0400 @@ -25,6 +25,7 @@ package java.util; import java.util.function.DoubleConsumer; +import java.util.stream.Collector; /** * A state object for collecting statistics such as count, min, max, sum, and @@ -35,24 +36,24 @@ * summary statistics on a stream of doubles with: *
{@code * DoubleSummaryStatistics stats = doubleStream.collect(DoubleSummaryStatistics::new, - * DoubleSummaryStatistics::accept, - * DoubleSummaryStatistics::combine); + * DoubleSummaryStatistics::accept, + * DoubleSummaryStatistics::combine); * }* *
{@code DoubleSummaryStatistics} can be used as a - * {@linkplain java.util.stream.Stream#reduce(java.util.function.BinaryOperator) reduction} + * {@linkplain java.util.stream.Stream#collect(Collector) reduction} * target for a {@linkplain java.util.stream.Stream stream}. For example: * *
{@code * DoubleSummaryStatistics stats = people.stream() - * .collect(Collectors.toDoubleSummaryStatistics(Person::getWeight)); + * .collect(Collectors.summarizingDouble(Person::getWeight)); *}* * This computes, in a single pass, the count of people, as well as the minimum, * maximum, sum, and average of their weights. * * @implNote This implementation is not thread safe. However, it is safe to use - * {@link java.util.stream.Collectors#toDoubleSummaryStatistics(java.util.function.ToDoubleFunction) + * {@link java.util.stream.Collectors#summarizingDouble(java.util.function.ToDoubleFunction) * Collectors.toDoubleStatistics()} on a parallel stream, because the parallel * implementation of {@link java.util.stream.Stream#collect Stream.collect()} * provides the necessary partitioning, isolation, and merging of results for @@ -152,7 +153,7 @@ } /** - * Returns the average of values recorded, or zero if no values have been + * Returns the arithmetic mean of values recorded, or zero if no values have been * recorded. The average returned can vary depending upon the order in * which values are recorded. This is due to accumulated rounding error in * addition of values of differing magnitudes. Values sorted by increasing @@ -160,7 +161,7 @@ * value is a {@code NaN} or the sum is at any point a {@code NaN} then the * average will be {@code NaN}. * - * @return the average of values, or zero if none + * @return the arithmetic mean of values, or zero if none */ public final double getAverage() { return getCount() > 0 ? getSum() / getCount() : 0.0d; diff -r c360667a0da2 -r e5901820c3c1 jdk/src/share/classes/java/util/IntSummaryStatistics.java --- a/jdk/src/share/classes/java/util/IntSummaryStatistics.java Tue Aug 06 16:01:39 2013 -0700 +++ b/jdk/src/share/classes/java/util/IntSummaryStatistics.java Fri Jun 28 16:26:54 2013 -0400 @@ -25,6 +25,7 @@ package java.util; import java.util.function.IntConsumer; +import java.util.stream.Collector; /** * A state object for collecting statistics such as count, min, max, sum, and @@ -35,24 +36,24 @@ * summary statistics on a stream of ints with: *
{@code * IntSummaryStatistics stats = intStream.collect(IntSummaryStatistics::new, - * IntSummaryStatistics::accept, - * IntSummaryStatistics::combine); + * IntSummaryStatistics::accept, + * IntSummaryStatistics::combine); * }* *
{@code IntSummaryStatistics} can be used as a - * {@linkplain java.util.stream.Stream#reduce(java.util.function.BinaryOperator) reduction} + * {@linkplain java.util.stream.Stream#collect(Collector) reduction} * target for a {@linkplain java.util.stream.Stream stream}. For example: * *
{@code * IntSummaryStatistics stats = people.stream() - * .collect(Collectors.toIntSummaryStatistics(Person::getDependents)); + * .collect(Collectors.summarizingInt(Person::getDependents)); *}* * This computes, in a single pass, the count of people, as well as the minimum, * maximum, sum, and average of their number of dependents. * * @implNote This implementation is not thread safe. However, it is safe to use - * {@link java.util.stream.Collectors#toIntSummaryStatistics(java.util.function.ToIntFunction) + * {@link java.util.stream.Collectors#summarizingInt(java.util.function.ToIntFunction) * Collectors.toIntStatistics()} on a parallel stream, because the parallel * implementation of {@link java.util.stream.Stream#collect Stream.collect()} * provides the necessary partitioning, isolation, and merging of results for @@ -140,10 +141,10 @@ } /** - * Returns the average of values recorded, or zero if no values have been + * Returns the arithmetic mean of values recorded, or zero if no values have been * recorded. * - * @return the average of values, or zero if none + * @return the arithmetic mean of values, or zero if none */ public final double getAverage() { return getCount() > 0 ? (double) getSum() / getCount() : 0.0d; diff -r c360667a0da2 -r e5901820c3c1 jdk/src/share/classes/java/util/LongSummaryStatistics.java --- a/jdk/src/share/classes/java/util/LongSummaryStatistics.java Tue Aug 06 16:01:39 2013 -0700 +++ b/jdk/src/share/classes/java/util/LongSummaryStatistics.java Fri Jun 28 16:26:54 2013 -0400 @@ -26,6 +26,7 @@ import java.util.function.IntConsumer; import java.util.function.LongConsumer; +import java.util.stream.Collector; /** * A state object for collecting statistics such as count, min, max, sum, and @@ -36,24 +37,24 @@ * summary statistics on a stream of longs with: *
{@code * LongSummaryStatistics stats = longStream.collect(LongSummaryStatistics::new, - * LongSummaryStatistics::accept, - * LongSummaryStatistics::combine); + * LongSummaryStatistics::accept, + * LongSummaryStatistics::combine); * }* *
{@code LongSummaryStatistics} can be used as a - * {@linkplain java.util.stream.Stream#reduce(java.util.function.BinaryOperator) reduction} + * {@linkplain java.util.stream.Stream#collect(Collector)} reduction} * target for a {@linkplain java.util.stream.Stream stream}. For example: * *
{@code * LongSummaryStatistics stats = people.stream() - * .collect(Collectors.toLongSummaryStatistics(Person::getAge)); + * .collect(Collectors.summarizingLong(Person::getAge)); *}* * This computes, in a single pass, the count of people, as well as the minimum, - * maximum, sum, and average of their ages in milliseconds. + * maximum, sum, and average of their ages. * * @implNote This implementation is not thread safe. However, it is safe to use - * {@link java.util.stream.Collectors#toLongSummaryStatistics(java.util.function.ToLongFunction) + * {@link java.util.stream.Collectors#summarizingLong(java.util.function.ToLongFunction) * Collectors.toLongStatistics()} on a parallel stream, because the parallel * implementation of {@link java.util.stream.Stream#collect Stream.collect()} * provides the necessary partitioning, isolation, and merging of results for @@ -152,10 +153,10 @@ } /** - * Returns the average of values recorded, or zero if no values have been + * Returns the arithmetic mean of values recorded, or zero if no values have been * recorded. * - * @return The average of values, or zero if none + * @return The arithmetic mean of values, or zero if none */ public final double getAverage() { return getCount() > 0 ? (double) getSum() / getCount() : 0.0d; diff -r c360667a0da2 -r e5901820c3c1 jdk/src/share/classes/java/util/StringJoiner.java --- a/jdk/src/share/classes/java/util/StringJoiner.java Tue Aug 06 16:01:39 2013 -0700 +++ b/jdk/src/share/classes/java/util/StringJoiner.java Fri Jun 28 16:26:54 2013 -0400 @@ -49,16 +49,17 @@ *
* A {@code StringJoiner} may be employed to create formatted output from a * {@link java.util.stream.Stream} using - * {@link java.util.stream.Collectors#toStringJoiner}. For example: + * {@link java.util.stream.Collectors#joining(CharSequence)}. For example: * *
{@code * List* - * @see java.util.stream.Collectors#toStringJoiner + * @see java.util.stream.Collectors#joining(CharSequence) + * @see java.util.stream.Collectors#joining(CharSequence, CharSequence, CharSequence) * @since 1.8 */ public final class StringJoiner { diff -r c360667a0da2 -r e5901820c3c1 jdk/src/share/classes/java/util/stream/Collector.java --- a/jdk/src/share/classes/java/util/stream/Collector.java Tue Aug 06 16:01:39 2013 -0700 +++ b/jdk/src/share/classes/java/util/stream/Collector.java Fri Jun 28 16:26:54 2013 -0400 @@ -25,40 +25,45 @@ package java.util.stream; import java.util.Collections; +import java.util.EnumSet; import java.util.Set; -import java.util.function.BiFunction; +import java.util.function.BiConsumer; import java.util.function.BinaryOperator; +import java.util.function.Function; import java.util.function.Supplier; /** * A reduction operation that - * supports folding input elements into a cumulative result. The result may be - * a value or may be a mutable result container. Examples of operations - * accumulating results into a mutable result container include: accumulating - * input elements into a {@code Collection}; concatenating strings into 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. + * folds input elements into a mutable result container, optionally transforming + * the accumulated result into a final representation after all input elements + * have been processed. + * + *numbers = Arrays.asList(1, 2, 3, 4); * String commaSeparatedNumbers = numbers.stream() * .map(i -> i.toString()) - * .collect(Collectors.toStringJoiner(", ")).toString(); + * .collect(Collectors.joining(", ")); * }
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 elements into a List - * List* - *list = stream.collect(Collectors.toList()); + * // Accumulate names into a List + * List list = people.stream().map(Person::getName).collect(Collectors.toList()); * - * // Accumulate elements into a TreeSet - * Set list = stream.collect(Collectors.toCollection(TreeSet::new)); + * // 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 = stream.map(Object::toString) - * .collect(Collectors.toStringJoiner(", ")) - * .toString(); + * 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))); + * .collect(Collectors.maxBy(Comparators.comparing(Employee::getSalary))) + * .get(); * * // Group employees by department * Map > byDept @@ -66,7 +71,7 @@ * .collect(Collectors.groupingBy(Employee::getDepartment)); * * // Find highest-paid employee by department - * Map highestPaidByDept + * Map > highestPaidByDept * = employees.stream() * .collect(Collectors.groupingBy(Employee::getDepartment, * Collectors.maxBy(Comparators.comparing(Employee::getSalary)))); @@ -74,43 +79,42 @@ * // Partition students into passing and failing * Map > passingFailing = * students.stream() - * .collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD); + * .collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD)); * * }
A {@code Collector} is specified by three functions that work together to - * manage a result or result container. They are: creation of an initial - * result, incorporating a new data element into a result, and combining two - * results into one. The last function -- combining two results into one -- is - * used during parallel operations, where subsets of the input are accumulated - * in parallel, and then the subresults merged into a combined result. The - * result may be a mutable container or a value. If the result is mutable, the - * accumulation and combination functions may either mutate their left argument - * and return that (such as adding elements to a collection), or return a new - * result, in which case it should not perform any mutation. + *
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, including - * {@link Characteristics#CONCURRENT} and - * {@link Characteristics#STRICTLY_MUTATIVE}. These characteristics provide + *
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: *
{@code - * BiFunction* *accumulator = collector.accumulator(); - * R result = collector.resultSupplier().get(); + * R container = collector.supplier().get(); * for (T t : data) - * result = accumulator.apply(result, t); - * return result; + * collector.accumulator().accept(container, t); + * return collector.finisher().apply(container); * }
However, the library is free to partition the input, perform the reduction
@@ -149,7 +152,7 @@
* is accumulating elements into a {@code TreeSet}. In this case, the {@code
* resultSupplier()} function is {@code () -> new Treeset If the collector has the {@link Characteristics#STRICTLY_MUTATIVE}
- * characteristic, then the accumulator function must always return
- * its first argument, after possibly mutating its state.
- *
- * @return a function which folds a new value into a cumulative result
+ * @return a function which folds a new value into a mutable result container
*/
- BiFunction If the collector has the {@link Characteristics#STRICTLY_MUTATIVE}
- * characteristic, then the combiner function must always return
- * its first argument, after possibly mutating its state.
+ * return that, or may return a new result object.
*
* @return a function which combines two partial results into a cumulative
* result
*/
- BinaryOperator 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
@@ -214,6 +215,62 @@
Set If a {@code CONCURRENT} collector is not also {@code UNORDERED},
* then it should only be evaluated concurrently if applied to an
@@ -238,12 +294,10 @@
UNORDERED,
/**
- * Indicates that this collector operates by strict mutation of its
- * result container. This means that the {@link #accumulator()} and
- * {@link #combiner()} functions will always modify the state of and
- * return their first argument, rather than returning a different result
- * container.
+ * 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.
*/
- STRICTLY_MUTATIVE
+ IDENTITY_FINISH
}
}
diff -r c360667a0da2 -r e5901820c3c1 jdk/src/share/classes/java/util/stream/Collectors.java
--- a/jdk/src/share/classes/java/util/stream/Collectors.java Tue Aug 06 16:01:39 2013 -0700
+++ b/jdk/src/share/classes/java/util/stream/Collectors.java Fri Jun 28 16:26:54 2013 -0400
@@ -27,6 +27,7 @@
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
@@ -39,14 +40,16 @@
import java.util.List;
import java.util.LongSummaryStatistics;
import java.util.Map;
-import java.util.NoSuchElementException;
import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
import java.util.StringJoiner;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.BinaryOperator;
+import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
@@ -64,20 +67,21 @@
* mutable reduction tasks:
*
* The sum returned can vary depending upon the order in which
+ * values are recorded, due to accumulated rounding error in
+ * addition of values of differing magnitudes. Values sorted by increasing
+ * absolute magnitude tend to yield more accurate results. If any recorded
+ * value is a {@code NaN} or the sum is at any point a {@code NaN} then the
+ * sum will be {@code NaN}.
*
* @param The average returned can vary depending upon the order in which
+ * values are recorded, due to accumulated rounding error in
+ * addition of values of differing magnitudes. Values sorted by increasing
+ * absolute magnitude tend to yield more accurate results. If any recorded
+ * value is a {@code NaN} or the sum is at any point a {@code NaN} then the
+ * average will be {@code NaN}.
+ *
+ * @param For example, given a stream of {@code Person}, to calculate the longest
* last name of residents in each city:
* The classification function maps elements to some key type {@code K}.
* The collector produces a {@code Map{@code
- * // Accumulate elements into a List
- * List
*
@@ -103,15 +107,19 @@
*/
public final class Collectors {
- private static final Set, T, List
> combiner = (left, right) -> {
- switch (left.size()) {
- case 0:
- return right;
- case 1:
- List
>) ArrayList::new, List::add,
+ (left, right) -> { left.addAll(right); return left; },
+ CH_ID);
}
/**
@@ -286,44 +243,58 @@
* {@code Set}
*/
public static
{@code
@@ -364,23 +336,27 @@
*
* @param
{@code
- * reducing(0L, mapper, Long::sum)
- * }
+ * @param {@code
* Comparator
- *
- * @implSpec
- * The default implementation is equivalent to:
- * {@code
- * reducing(null, op);
+ * = people.stream().collect(groupingBy(Person::getCity, reducing(BinaryOperator.maxBy(byHeight))));
* }
*
* @param {@code
* Comparator
*
* @param