changeset 7816:1997e4b4c4dd

More specification for Collectors; add counting() collector
author briangoetz
date Thu, 04 Apr 2013 17:38:39 -0400
parents 4a801290864f
children a79e2c6b28bb
files src/share/classes/java/util/stream/Collectors.java
diffstat 1 files changed, 157 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/java/util/stream/Collectors.java	Thu Apr 04 14:20:42 2013 -0400
+++ b/src/share/classes/java/util/stream/Collectors.java	Thu Apr 04 17:38:39 2013 -0400
@@ -71,7 +71,7 @@
             = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.STRICTLY_MUTATIVE,
                                                      Collector.Characteristics.UNORDERED));
 
-    private Collectors() {}
+    private Collectors() { }
 
     /**
      * Return a merge function, suitable for use in {@link Map#merge(Object, Object, BiFunction)} or
@@ -81,11 +81,36 @@
      * @param <T> The type of input arguments to the merge function
      * @return A merge function which always throw {@code IllegalStateException}
      */
-    public static<T> BinaryOperator<T> throwingMergeFunction() {
+    public static<T> BinaryOperator<T> throwingMerger() {
         return (u,v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); };
     }
 
-    static final class CollectorImpl<T, R> implements Collector<T,R> {
+    /**
+     * Return a merge function, suitable for use in {@link Map#merge(Object, Object, BiFunction)} or
+     * {@link #toMap(Function, Supplier, BinaryOperator)}, which implements a "first wins"
+     * policy.
+     *
+     * @param <T> The type of input arguments to the merge function
+     * @return A merge function which always returns its first argument
+     */
+    public static<T> BinaryOperator<T> firstWinsMerger() {
+        return (u,v) -> u;
+    }
+
+    /**
+     * Return a merge function, suitable for use in {@link Map#merge(Object, Object, BiFunction)} or
+     * {@link #toMap(Function, Supplier, BinaryOperator)}, which implements a "last wins"
+     * policy.
+     *
+     * @param <T> The type of input arguments to the merge function
+     * @return A merge function which always returns its second argument
+     */
+    public static<T> BinaryOperator<T> lastWinsMerger() {
+        return (u,v) -> v;
+    }
+
+    /** Simple implementation class for {@code Collector} */
+    private static final class CollectorImpl<T, R> implements Collector<T,R> {
         private final Supplier<R> resultSupplier;
         private final BiFunction<R, T, R> accumulator;
         private final BinaryOperator<R> combiner;
@@ -130,14 +155,14 @@
 
     /**
      * Return a {@code Collector} that accumulates the input elements into a new {@code Collection},
-     * which is created by the provided factory.
+     * in encounter order.  The {@code Collection} is created by the provided factory.
      *
      * @param collectionFactory A {@code Supplier} which returns a new, empty {@code Collection}
-     *                          of the appropriate type each time it is called
+     *                          of the appropriate type
      * @param <T> The type of the input elements
      * @param <C> The type of the resulting {@code Collection}
-     * @return A {@code Collector} which collects elements into a {@code Collection} containing all the input elements
-     * , in encounter order
+     * @return A {@code Collector} which collects all the input elements into a
+     * {@code Collection}, in encounter order
      */
     public static<T, C extends Collection<T>>
     Collector<T, C> toCollection(Supplier<C> collectionFactory) {
@@ -153,8 +178,8 @@
      * returned, and the returned list is not guaranteed to be mutable.
      *
      * @param <T> The type of the input elements
-     * @return A {@code Collector} which collects elements into a {@code List} containing all the input elements,
-     * in encounter order
+     * @return A {@code Collector} which collects all the input elements into a
+     * {@code List}, in encounter order
      */
     public static<T>
     Collector<T, List<T>> toList() {
@@ -195,7 +220,8 @@
      * returned, and the returned list is not guaranteed to be mutable.
      *
      * @param <T> The type of the input elements
-     * @return A {@code Collector} which collects elements into a {@code Set} containing all the input elements
+     * @return A {@code Collector} which collects all the input elements into a
+     * {@code Set}
      */
     public static<T>
     Collector<T, Set<T>> toSet() {
@@ -206,10 +232,11 @@
     }
 
     /**
-     * Return a {@code Collector} that concatenates the input elements into a new {@code StringBuilder}.
+     * Return a {@code Collector} that concatenates the input elements into a new
+     * {@code StringBuilder}.
      *
-     * @return A {@code Collector} which collects {@code String} elements into a {@code StringBuilder} containing
-     * all of the input elements concatenated in encounter order
+     * @return A {@code Collector} which collects String elements into a
+     * {@code StringBuilder}, in encounter order
      */
     public static Collector<String, StringBuilder> toStringBuilder() {
         return new CollectorImpl<>(StringBuilder::new,
@@ -219,11 +246,11 @@
     }
 
     /**
-     * Return a {@code Collector} that concatenates the input elements into a new {@code StringJoiner},
-     * using the specified separator.
+     * Return a {@code Collector} that concatenates the input elements into a new
+     * {@code StringJoiner}, using the specified separator.
      *
-     * @return A {@code Collector} which collects String elements into a {@code StringJoiner} containing all of
-     * the input elements concatenated in encounter order
+     * @return A {@code Collector} which collects String elements into a
+     * {@code StringJoiner}, in encounter order
      */
     public static Collector<CharSequence, StringJoiner> toStringJoiner(String separator) {
         BinaryOperator<StringJoiner> merger = (sj, other) -> {
@@ -235,6 +262,14 @@
                                    merger, CH_STRICT);
     }
 
+    /** BinaryOperator<Map> that merges the contents of its right argument into its left
+     * argument, using the provided merge function to handle duplicate keys
+     * @param mergeFunction A merge function suitable for {@link Map#merge(Object, Object, BiFunction)}
+     * @param <K> Type of the map keys
+     * @param <V> Type of the map values
+     * @param <M> Type of the map
+     * @return A merge function for two maps
+     */
     private static<K, V, M extends Map<K,V>> BinaryOperator<M> mapMerger(BinaryOperator<V> mergeFunction) {
         return (m1, m2) -> {
             for (Map.Entry<K,V> e : m2.entrySet())
@@ -276,8 +311,8 @@
     }
 
     /**
-     * Given a {@code BinaryOperator<T>}, return a {@code Collector<T,T>} which calculates the reduction of
-     * its input elements under the specified {@code BinaryOperator}.
+     * Given a {@code BinaryOperator<T>}, return a {@code Collector<T,T>} which calculates the
+     * reduction of its input elements under the specified {@code BinaryOperator}.
      *
      * @apiNote
      * The {@code reducing()} collectors are most useful when used in a multi-level collection
@@ -301,6 +336,22 @@
     }
 
     /**
+     * Produces a {@code Collector<T, Long>} that counts the number of input elements.
+     *
+     * @implSpec
+     * This produces a result equivalent to:
+     * <pre>
+     *     reducing(e -> 1L, Long::sum)
+     * </pre>
+     * @param <T> The type of the input elements
+     * @return A {@code Collector} that counts its input elements
+     */
+    public static<T> Collector<T, Long>
+    counting() {
+        return reducing(e -> 1L, Long::sum);
+    }
+
+    /**
      * Given a {@code BinaryOperator<U>} and a {@code Function<T,U>}, return a {@code Collector<T,U>}
      * which calculates the reduction of the input elements after applying the mapping function.
      * This is a generalization of {@link #reducing(BinaryOperator)}, which allows a transformation of
@@ -444,23 +495,108 @@
         return new CollectorImpl<>(mapFactory, accumulator, mapMerger(downstream.combiner()), CH_STRICT);
     }
 
+    /**
+     * Returns a {@code Collector} that implements a concurrent "group by" operation on input
+     * elements of type {@code T}.
+     * <p>This is a <em>concurrent</em> Collector.  (TODO need reference).
+     *
+     * <p>Accepts a classification function from {@code T} to {@code K}.  The collector produces
+     * a {@code ConcurrentMap} whose keys are the set of values resulting of applying the
+     * classification function to the input elements, and whose corresponding values are
+     * {@code List}s containing the input elements which map to the associated key under the
+     * classification function.
+     *
+     * <p>No guarantees are made as to the type of the {@code ConcurrentMap} or the type of the
+     * {@code List} used for the map values.
+     *
+     * @param classifier The classifier function mapping input elements to keys
+     * @param <T> The type of the input elements
+     * @param <K> The type of the keys
+     * @return A {@code Collector} implementing the group-by operation
+     */
     public static<T, K>
     Collector<T, ConcurrentMap<K, List<T>>> groupingByConcurrent(Function<? super T, ? extends K> classifier) {
         return groupingByConcurrent(classifier, ConcurrentHashMap::new);
     }
 
+    /**
+     * Returns a {@code Collector} that implements a concurrent "group by" operation on input
+     * elements of type {@code T}, resulting in a {@code Map} of a specific type.
+     * <p>This is a <em>concurrent</em> Collector.  (TODO need reference).
+     *
+     * <p>Accepts a classification function from {@code T} to {@code K}, and a factory function
+     * which produces a {@code ConcurrentMap} of the desired type.  The collector populates
+     * the {@code ConcurrentMap} produced by the factory function, whose keys are the set of
+     * values resulting of applying the classification function to the input elements, and
+     * whose corresponding values are {@code List}s containing the input elements which map to
+     * the associated key under the classification function.
+     *
+     * <p>No guarantees are made as to the type of the {@code List} used for the map values.
+     *
+     * @param classifier The classifier function mapping input elements to keys
+     * @param mapFactory A function which, when invoked, returns a new, empty instance
+     *                   of a {@code Map} of the desired type
+     * @param <M> The type of the resulting {@code Map}
+     * @param <T> The type of the input elements
+     * @param <K> The type of the keys
+     * @return A {@code Collector} implementing the group-by operation
+     * @return
+     */
     public static<T, K, M extends ConcurrentMap<K, List<T>>>
     Collector<T, M> groupingByConcurrent(Function<? super T, ? extends K> classifier,
                                          Supplier<M> mapFactory) {
         return groupingByConcurrent(classifier, mapFactory, toList());
     }
 
+    /**
+     * Returns a {@code Collector} that implements a concurrent cascaded "group by" operation on
+     * input elements of type {@code T}, resulting in a {@code ConcurrentMap} whose values are
+     * the result of another reduction, resulting in a {@code ConcurrentMap} of a specific type.
+     * <p>This is a <em>concurrent</em> Collector.  (TODO need reference).
+     *
+     * <p>Accepts a classification function from {@code T} to {@code K} and a {@code Collector}
+     * which implements another reduction on elements of type {@code T}.  The collector populates
+     * a {@code ConcurrentMap} whose keys are the set of values resulting of applying the
+     * classification function to the input elements, and whose corresponding values are the
+     * result of reducing the input elements which map to the associated key under the
+     * classification function with the dowstream reducer.
+     *
+     * <p>No guarantees are made as to the type of the resulting {@code Map}.
+     *
+     * @param classifier The classifier function mapping input elements to keys
+     * @param downstream A {@code Collector} implementing the downstream reduction
+     * @param <T> The type of the input elements
+     * @param <K> The type of the keys
+     * @param <D> The result type of the downstream reduction
+     * @return A {@code Collector} implementing the cascaded group-by operation
+     */
     public static<T, K, D>
     Collector<T, ConcurrentMap<K, D>> groupingByConcurrent(Function<? super T, ? extends K> classifier,
                                                            Collector<T, D> downstream) {
         return groupingByConcurrent(classifier, ConcurrentHashMap::new, downstream);
     }
 
+    /**
+     * Returns a {@code Collector} that implements a cascaded concurrent "group by" operation on
+     * input elements of type {@code T}, resulting in a {@code ConcurrentMap} whose values are
+     * the result of another reduction.
+     * <p>This is a <em>concurrent</em> Collector.  (TODO need reference).
+     *
+     * <p>Accepts a classification function from {@code T} to {@code K}, a factory function
+     * which produces a {@code ConcurrentMap} of the desired type, and a {@code Collector} which
+     * implements another reduction on elements of type {@code T}.  The collector populates a
+     * {@code ConcurrentMap} produced by the factory function whose keys are the set of values
+     * resulting of applying the classification function to the input elements, and whose
+     * corresponding values are the result of reducing the input elements which map to the
+     * associated key under the classification function with the dowstream reducer.
+     *
+     * @param classifier The classifier function mapping input elements to keys
+     * @param downstream A {@code Collector} implementing the downstream reduction
+     * @param <T> The type of the input elements
+     * @param <K> The type of the keys
+     * @param <D> The result type of the downstream reduction
+     * @return A {@code Collector} implementing the cascaded group-by operation
+     */
     public static<T, K, D, M extends ConcurrentMap<K, D>>
     Collector<T, M> groupingByConcurrent(Function<? super T, ? extends K> classifier,
                                          Supplier<M> mapFactory,
@@ -592,7 +728,7 @@
      * and whose values are the result of applying the mapping function to the input element
      */
     public static <T, U> Collector<T, Map<T,U>> toMap(Function<? super T, ? extends U> mapper) {
-        return toMap(mapper, HashMap::new, throwingMergeFunction());
+        return toMap(mapper, HashMap::new, throwingMerger());
     }
 
     /**
@@ -637,7 +773,7 @@
      */
     public static <T, U>
     Collector<T, ConcurrentMap<T,U>> toConcurrentMap(Function<? super T, ? extends U> mapper) {
-        return toConcurrentMap(mapper, ConcurrentHashMap::new, throwingMergeFunction());
+        return toConcurrentMap(mapper, ConcurrentHashMap::new, throwingMerger());
     }
 
     /**