< prev index next >

## src/java.base/share/classes/java/util/stream/Collectors.java

Print this page

    rev 48045 : 8177290: add copy factory methods for unmodifiable List, Set, Map
    8184690: add Collectors for collecting into unmodifiable List, Set, and Map
    Reviewed-by: alanb, briangoetz, dholmes, jrose, rriggs, scolebourne

       1 /*
       2  * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
       3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       4  *
       5  * This code is free software; you can redistribute it and/or modify it
       6  * under the terms of the GNU General Public License version 2 only, as
       7  * published by the Free Software Foundation.  Oracle designates this
       8  * particular file as subject to the "Classpath" exception as provided
       9  * by Oracle in the LICENSE file that accompanied this code.
      10  *
      11  * This code is distributed in the hope that it will be useful, but WITHOUT
      12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      14  * version 2 for more details (a copy is included in the LICENSE file that
      15  * accompanied this code).
      16  *
      17  * You should have received a copy of the GNU General Public License version
      18  * 2 along with this work; if not, write to the Free Software Foundation,
      19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
      20  *
      21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
      22  * or visit www.oracle.com if you need additional information or have any
      99  *
     100  * }</pre>
     101  *
     102  * @since 1.8
     103  */
     104 public final class Collectors {
     105
     106     static final Set<Collector.Characteristics> CH_CONCURRENT_ID
     107             = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.CONCURRENT,
     108                                                      Collector.Characteristics.UNORDERED,
     109                                                      Collector.Characteristics.IDENTITY_FINISH));
     110     static final Set<Collector.Characteristics> CH_CONCURRENT_NOID
     111             = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.CONCURRENT,
     112                                                      Collector.Characteristics.UNORDERED));
     113     static final Set<Collector.Characteristics> CH_ID
     114             = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH));
     115     static final Set<Collector.Characteristics> CH_UNORDERED_ID
     116             = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.UNORDERED,
     117                                                      Collector.Characteristics.IDENTITY_FINISH));
     118     static final Set<Collector.Characteristics> CH_NOID = Collections.emptySet();

     119
     120     private Collectors() { }
     121
     122     /**
     123      * Construct an {@code IllegalStateException} with appropriate message.
     124      *
     125      * @param k the duplicate key
     126      * @param u 1st value to be accumulated/merged
     127      * @param v 2nd value to be accumulated/merged
     128      */
     129     private static IllegalStateException duplicateKeyException(
     130             Object k, Object u, Object v) {
     131         return new IllegalStateException(String.format(
     132             "Duplicate key %s (attempted merging values %s and %s)",
     133             k, u, v));
     134     }
     135
     136     /**
     137      * {@code BinaryOperator<Map>} that merges the contents of its right
     138      * argument into its left argument, throwing {@code IllegalStateException}
     262     }
     263
     264     /**
     265      * Returns a {@code Collector} that accumulates the input elements into a
     266      * new {@code List}. There are no guarantees on the type, mutability,
     267      * serializability, or thread-safety of the {@code List} returned; if more
     268      * control over the returned {@code List} is required, use {@link #toCollection(Supplier)}.
     269      *
     270      * @param <T> the type of the input elements
     271      * @return a {@code Collector} which collects all the input elements into a
     272      * {@code List}, in encounter order
     273      */
     274     public static <T>
     275     Collector<T, ?, List<T>> toList() {
     276         return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
     277                                    (left, right) -> { left.addAll(right); return left; },
     278                                    CH_ID);
     279     }
     280
     281     /**

     282      * Returns a {@code Collector} that accumulates the input elements into a
     283      * new {@code Set}. There are no guarantees on the type, mutability,
     284      * serializability, or thread-safety of the {@code Set} returned; if more
     285      * control over the returned {@code Set} is required, use
     286      * {@link #toCollection(Supplier)}.
     287      *
     288      * <p>This is an {@link Collector.Characteristics#UNORDERED unordered}
     289      * Collector.
     290      *
     291      * @param <T> the type of the input elements
     292      * @return a {@code Collector} which collects all the input elements into a
     293      * {@code Set}
     294      */
     295     public static <T>
     296     Collector<T, ?, Set<T>> toSet() {
     297         return new CollectorImpl<>((Supplier<Set<T>>) HashSet::new, Set::add,
     298                                    (left, right) -> {
     299                                        if (left.size() < right.size()) {
     300                                            right.addAll(left); return right;
     301                                        } else {
     302                                            left.addAll(right); return left;
     303                                        }
     304                                    },
     305                                    CH_UNORDERED_ID);
     306     }
     307
     308     /**

     309      * Returns a {@code Collector} that concatenates the input elements into a
     310      * {@code String}, in encounter order.
     311      *
     312      * @return a {@code Collector} that concatenates the input elements into a
     313      * {@code String}, in encounter order
     314      */
     315     public static Collector<CharSequence, ?, String> joining() {
     316         return new CollectorImpl<CharSequence, StringBuilder, String>(
     317                 StringBuilder::new, StringBuilder::append,
     318                 (r1, r2) -> { r1.append(r2); return r1; },
     319                 StringBuilder::toString, CH_NOID);
     320     }
     321
     322     /**
     323      * Returns a {@code Collector} that concatenates the input elements,
     324      * separated by the specified delimiter, in encounter order.
     325      *
     326      * @param delimiter the delimiter to be used between each element
     327      * @return A {@code Collector} which concatenates CharSequence elements,
     328      * separated by the specified delimiter, in encounter order
    1336                                 downstream.supplier().get());
    1337         if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
    1338             return new CollectorImpl<>(supplier, accumulator, merger, CH_ID);
    1339         }
    1340         else {
    1341             Function<Partition<A>, Map<Boolean, D>> finisher = par ->
    1342                     new Partition<>(downstream.finisher().apply(par.forTrue),
    1343                                     downstream.finisher().apply(par.forFalse));
    1344             return new CollectorImpl<>(supplier, accumulator, merger, finisher, CH_NOID);
    1345         }
    1346     }
    1347
    1348     /**
    1349      * Returns a {@code Collector} that accumulates elements into a
    1350      * {@code Map} whose keys and values are the result of applying the provided
    1351      * mapping functions to the input elements.
    1352      *
    1353      * <p>If the mapped keys contain duplicates (according to
    1354      * {@link Object#equals(Object)}), an {@code IllegalStateException} is
    1355      * thrown when the collection operation is performed.  If the mapped keys
    1356      * may have duplicates, use {@link #toMap(Function, Function, BinaryOperator)}
    1357      * instead.
    1358      *
    1359      * <p>There are no guarantees on the type, mutability, serializability,
    1360      * or thread-safety of the {@code Map} returned.
    1361      *
    1362      * @apiNote
    1363      * It is common for either the key or the value to be the input elements.
    1364      * In this case, the utility method
    1365      * {@link java.util.function.Function#identity()} may be helpful.
    1366      * For example, the following produces a {@code Map} mapping
    1367      * students to their grade point average:
    1368      * <pre>{@code
    1369      * Map<Student, Double> studentToGPA
    1370      *   = students.stream().collect(
    1371      *     toMap(Function.identity(),
    1372      *           student -> computeGPA(student)));
    1373      * }</pre>
    1374      * And the following produces a {@code Map} mapping a unique identifier to
    1375      * students:
    1376      * <pre>{@code
    1394      * @param keyMapper a mapping function to produce keys
    1395      * @param valueMapper a mapping function to produce values
    1396      * @return a {@code Collector} which collects elements into a {@code Map}
    1397      * whose keys and values are the result of applying mapping functions to
    1398      * the input elements
    1399      *
    1400      * @see #toMap(Function, Function, BinaryOperator)
    1401      * @see #toMap(Function, Function, BinaryOperator, Supplier)
    1402      * @see #toConcurrentMap(Function, Function)
    1403      */
    1404     public static <T, K, U>
    1405     Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
    1406                                     Function<? super T, ? extends U> valueMapper) {
    1407         return new CollectorImpl<>(HashMap::new,
    1408                                    uniqKeysMapAccumulator(keyMapper, valueMapper),
    1409                                    uniqKeysMapMerger(),
    1410                                    CH_ID);
    1411     }
    1412
    1413     /**

    1414      * Returns a {@code Collector} that accumulates elements into a
    1415      * {@code Map} whose keys and values are the result of applying the provided
    1416      * mapping functions to the input elements.
    1417      *
    1418      * <p>If the mapped
    1419      * keys contain duplicates (according to {@link Object#equals(Object)}),
    1420      * the value mapping function is applied to each equal element, and the
    1421      * results are merged using the provided merging function.
    1422      *
    1423      * <p>There are no guarantees on the type, mutability, serializability,
    1424      * or thread-safety of the {@code Map} returned.
    1425      *
    1426      * @apiNote
    1427      * There are multiple ways to deal with collisions between multiple elements
    1428      * mapping to the same key.  The other forms of {@code toMap} simply use
    1429      * a merge function that throws unconditionally, but you can easily write
    1430      * more flexible merge policies.  For example, if you have a stream
    1431      * of {@code Person}, and you want to produce a "phone book" mapping name to
    1432      * address, but it is possible that two persons have the same name, you can
    1433      * do as follows to gracefully deal with these collisions, and produce a
    1456      * @param mergeFunction a merge function, used to resolve collisions between
    1457      *                      values associated with the same key, as supplied
    1458      *                      to {@link Map#merge(Object, Object, BiFunction)}
    1459      * @return a {@code Collector} which collects elements into a {@code Map}
    1460      * whose keys are the result of applying a key mapping function to the input
    1461      * elements, and whose values are the result of applying a value mapping
    1462      * function to all input elements equal to the key and combining them
    1463      * using the merge function
    1464      *
    1465      * @see #toMap(Function, Function)
    1466      * @see #toMap(Function, Function, BinaryOperator, Supplier)
    1467      * @see #toConcurrentMap(Function, Function, BinaryOperator)
    1468      */
    1469     public static <T, K, U>
    1470     Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
    1471                                     Function<? super T, ? extends U> valueMapper,
    1472                                     BinaryOperator<U> mergeFunction) {
    1473         return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);
    1474     }
    1475

    1476     /**
    1477      * Returns a {@code Collector} that accumulates elements into a
    1478      * {@code Map} whose keys and values are the result of applying the provided
    1479      * mapping functions to the input elements.
    1480      *
    1481      * <p>If the mapped
    1482      * keys contain duplicates (according to {@link Object#equals(Object)}),
    1483      * the value mapping function is applied to each equal element, and the
    1484      * results are merged using the provided merging function.  The {@code Map}
    1485      * is created by a provided supplier function.
    1486      *
    1487      * @implNote
    1488      * The returned {@code Collector} is not concurrent.  For parallel stream
    1489      * pipelines, the {@code combiner} function operates by merging the keys
    1490      * from one map into another, which can be an expensive operation.  If it is
    1491      * not required that results are merged into the {@code Map} in encounter
    1492      * order, using {@link #toConcurrentMap(Function, Function, BinaryOperator, Supplier)}
    1493      * may offer better parallel performance.
    1494      *
    1495      * @param <T> the type of the input elements
       1 /*
       2  * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
       3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       4  *
       5  * This code is free software; you can redistribute it and/or modify it
       6  * under the terms of the GNU General Public License version 2 only, as
       7  * published by the Free Software Foundation.  Oracle designates this
       8  * particular file as subject to the "Classpath" exception as provided
       9  * by Oracle in the LICENSE file that accompanied this code.
      10  *
      11  * This code is distributed in the hope that it will be useful, but WITHOUT
      12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      14  * version 2 for more details (a copy is included in the LICENSE file that
      15  * accompanied this code).
      16  *
      17  * You should have received a copy of the GNU General Public License version
      18  * 2 along with this work; if not, write to the Free Software Foundation,
      19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
      20  *
      21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
      22  * or visit www.oracle.com if you need additional information or have any
      99  *
     100  * }</pre>
     101  *
     102  * @since 1.8
     103  */
     104 public final class Collectors {
     105
     106     static final Set<Collector.Characteristics> CH_CONCURRENT_ID
     107             = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.CONCURRENT,
     108                                                      Collector.Characteristics.UNORDERED,
     109                                                      Collector.Characteristics.IDENTITY_FINISH));
     110     static final Set<Collector.Characteristics> CH_CONCURRENT_NOID
     111             = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.CONCURRENT,
     112                                                      Collector.Characteristics.UNORDERED));
     113     static final Set<Collector.Characteristics> CH_ID
     114             = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH));
     115     static final Set<Collector.Characteristics> CH_UNORDERED_ID
     116             = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.UNORDERED,
     117                                                      Collector.Characteristics.IDENTITY_FINISH));
     118     static final Set<Collector.Characteristics> CH_NOID = Collections.emptySet();
     119     static final Set<Collector.Characteristics> CH_UNORDERED_NOID
     120             = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.UNORDERED));
     121
     122     private Collectors() { }
     123
     124     /**
     125      * Construct an {@code IllegalStateException} with appropriate message.
     126      *
     127      * @param k the duplicate key
     128      * @param u 1st value to be accumulated/merged
     129      * @param v 2nd value to be accumulated/merged
     130      */
     131     private static IllegalStateException duplicateKeyException(
     132             Object k, Object u, Object v) {
     133         return new IllegalStateException(String.format(
     134             "Duplicate key %s (attempted merging values %s and %s)",
     135             k, u, v));
     136     }
     137
     138     /**
     139      * {@code BinaryOperator<Map>} that merges the contents of its right
     140      * argument into its left argument, throwing {@code IllegalStateException}
     264     }
     265
     266     /**
     267      * Returns a {@code Collector} that accumulates the input elements into a
     268      * new {@code List}. There are no guarantees on the type, mutability,
     269      * serializability, or thread-safety of the {@code List} returned; if more
     270      * control over the returned {@code List} is required, use {@link #toCollection(Supplier)}.
     271      *
     272      * @param <T> the type of the input elements
     273      * @return a {@code Collector} which collects all the input elements into a
     274      * {@code List}, in encounter order
     275      */
     276     public static <T>
     277     Collector<T, ?, List<T>> toList() {
     278         return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
     279                                    (left, right) -> { left.addAll(right); return left; },
     280                                    CH_ID);
     281     }
     282
     283     /**
     284      * Returns a {@code Collector} that accumulates the input elements into an
     285      * <a href="../List.html#unmodifiable">unmodifiable List</a> in encounter
     286      * order. The returned Collector disallows null values and will throw
     287      * {@code NullPointerException} if it is presented with a null value.
     288      *
     289      * @param <T> the type of the input elements
     290      * @return a {@code Collector} that accumulates the input elements into an
     291      * <a href="../List.html#unmodifiable">unmodifiable List</a> in encounter order
     292      * @since 10
     293      */
     294     @SuppressWarnings("unchecked")
     295     public static <T>
     296     Collector<T, ?, List<T>> toUnmodifiableList() {
     297         return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
     298                                    (left, right) -> { left.addAll(right); return left; },
     299                                    list -> (List<T>)List.of(list.toArray()),
     300                                    CH_NOID);
     301     }
     302
     303     /**
     304      * Returns a {@code Collector} that accumulates the input elements into a
     305      * new {@code Set}. There are no guarantees on the type, mutability,
     306      * serializability, or thread-safety of the {@code Set} returned; if more
     307      * control over the returned {@code Set} is required, use
     308      * {@link #toCollection(Supplier)}.
     309      *
     310      * <p>This is an {@link Collector.Characteristics#UNORDERED unordered}
     311      * Collector.
     312      *
     313      * @param <T> the type of the input elements
     314      * @return a {@code Collector} which collects all the input elements into a
     315      * {@code Set}
     316      */
     317     public static <T>
     318     Collector<T, ?, Set<T>> toSet() {
     319         return new CollectorImpl<>((Supplier<Set<T>>) HashSet::new, Set::add,
     320                                    (left, right) -> {
     321                                        if (left.size() < right.size()) {
     322                                            right.addAll(left); return right;
     323                                        } else {
     324                                            left.addAll(right); return left;
     325                                        }
     326                                    },
     327                                    CH_UNORDERED_ID);
     328     }
     329
     330     /**
     331      * Returns a {@code Collector} that accumulates the input elements into an
     332      * <a href="../Set.html#unmodifiable">unmodifiable Set</a>. The returned
     333      * Collector disallows null values and will throw {@code NullPointerException}
     334      * if it is presented with a null value. If the input contains duplicate elements,
     335      * an arbitrary element of the duplicates is preserved.
     336      *
     337      * <p>This is an {@link Collector.Characteristics#UNORDERED unordered}
     338      * Collector.
     339      *
     340      * @param <T> the type of the input elements
     341      * @return a {@code Collector} that accumulates the input elements into an
     342      * <a href="../Set.html#unmodifiable">unmodifiable Set</a>
     343      * @since 10
     344      */
     345     @SuppressWarnings("unchecked")
     346     public static <T>
     347     Collector<T, ?, Set<T>> toUnmodifiableSet() {
     348         return new CollectorImpl<>((Supplier<Set<T>>) HashSet::new, Set::add,
     349                                    (left, right) -> {
     350                                        if (left.size() < right.size()) {
     351                                            right.addAll(left); return right;
     352                                        } else {
     353                                            left.addAll(right); return left;
     354                                        }
     355                                    },
     356                                    set -> (Set<T>)Set.of(set.toArray()),
     357                                    CH_UNORDERED_NOID);
     358     }
     359
     360     /**
     361      * Returns a {@code Collector} that concatenates the input elements into a
     362      * {@code String}, in encounter order.
     363      *
     364      * @return a {@code Collector} that concatenates the input elements into a
     365      * {@code String}, in encounter order
     366      */
     367     public static Collector<CharSequence, ?, String> joining() {
     368         return new CollectorImpl<CharSequence, StringBuilder, String>(
     369                 StringBuilder::new, StringBuilder::append,
     370                 (r1, r2) -> { r1.append(r2); return r1; },
     371                 StringBuilder::toString, CH_NOID);
     372     }
     373
     374     /**
     375      * Returns a {@code Collector} that concatenates the input elements,
     376      * separated by the specified delimiter, in encounter order.
     377      *
     378      * @param delimiter the delimiter to be used between each element
     379      * @return A {@code Collector} which concatenates CharSequence elements,
     380      * separated by the specified delimiter, in encounter order
    1388                                 downstream.supplier().get());
    1389         if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
    1390             return new CollectorImpl<>(supplier, accumulator, merger, CH_ID);
    1391         }
    1392         else {
    1393             Function<Partition<A>, Map<Boolean, D>> finisher = par ->
    1394                     new Partition<>(downstream.finisher().apply(par.forTrue),
    1395                                     downstream.finisher().apply(par.forFalse));
    1396             return new CollectorImpl<>(supplier, accumulator, merger, finisher, CH_NOID);
    1397         }
    1398     }
    1399
    1400     /**
    1401      * Returns a {@code Collector} that accumulates elements into a
    1402      * {@code Map} whose keys and values are the result of applying the provided
    1403      * mapping functions to the input elements.
    1404      *
    1405      * <p>If the mapped keys contain duplicates (according to
    1406      * {@link Object#equals(Object)}), an {@code IllegalStateException} is
    1407      * thrown when the collection operation is performed.  If the mapped keys
    1408      * might have duplicates, use {@link #toMap(Function, Function, BinaryOperator)}
    1409      * instead.
    1410      *
    1411      * <p>There are no guarantees on the type, mutability, serializability,
    1412      * or thread-safety of the {@code Map} returned.
    1413      *
    1414      * @apiNote
    1415      * It is common for either the key or the value to be the input elements.
    1416      * In this case, the utility method
    1417      * {@link java.util.function.Function#identity()} may be helpful.
    1418      * For example, the following produces a {@code Map} mapping
    1419      * students to their grade point average:
    1420      * <pre>{@code
    1421      * Map<Student, Double> studentToGPA
    1422      *   = students.stream().collect(
    1423      *     toMap(Function.identity(),
    1424      *           student -> computeGPA(student)));
    1425      * }</pre>
    1426      * And the following produces a {@code Map} mapping a unique identifier to
    1427      * students:
    1428      * <pre>{@code
    1446      * @param keyMapper a mapping function to produce keys
    1447      * @param valueMapper a mapping function to produce values
    1448      * @return a {@code Collector} which collects elements into a {@code Map}
    1449      * whose keys and values are the result of applying mapping functions to
    1450      * the input elements
    1451      *
    1452      * @see #toMap(Function, Function, BinaryOperator)
    1453      * @see #toMap(Function, Function, BinaryOperator, Supplier)
    1454      * @see #toConcurrentMap(Function, Function)
    1455      */
    1456     public static <T, K, U>
    1457     Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
    1458                                     Function<? super T, ? extends U> valueMapper) {
    1459         return new CollectorImpl<>(HashMap::new,
    1460                                    uniqKeysMapAccumulator(keyMapper, valueMapper),
    1461                                    uniqKeysMapMerger(),
    1462                                    CH_ID);
    1463     }
    1464
    1465     /**
    1466      * Returns a {@code Collector} that accumulates the input elements into an
    1467      * <a href="../Map.html#unmodifiable">unmodifiable Map</a>,
    1468      * whose keys and values are the result of applying the provided
    1469      * mapping functions to the input elements.
    1470      *
    1471      * <p>If the mapped keys contain duplicates (according to
    1472      * {@link Object#equals(Object)}), an {@code IllegalStateException} is
    1473      * thrown when the collection operation is performed.  If the mapped keys
    1474      * might have duplicates, use {@link #toUnmodifiableMap(Function, Function, BinaryOperator)}
    1475      * to handle merging of the values.
    1476      *
    1477      * <p>The returned Collector disallows null keys and values. If either mapping function
    1478      * returns null, {@code NullPointerException} will be thrown.
    1479      *
    1480      * @param <T> the type of the input elements
    1481      * @param <K> the output type of the key mapping function
    1482      * @param <U> the output type of the value mapping function
    1483      * @param keyMapper a mapping function to produce keys, must be non-null
    1484      * @param valueMapper a mapping function to produce values, must be non-null
    1485      * @return a {@code Collector} that accumulates the input elements into an
    1486      * <a href="../Map.html#unmodifiable">unmodifiable Map</a>, whose keys and values
    1487      * are the result of applying the provided mapping functions to the input elements
    1488      * @throws NullPointerException if either keyMapper or valueMapper is null
    1489      *
    1490      * @see #toUnmodifiableMap(Function, Function, BinaryOperator)
    1491      * @since 10
    1492      */
    1493     @SuppressWarnings({"rawtypes", "unchecked"})
    1494     public static <T, K, U>
    1495     Collector<T, ?, Map<K,U>> toUnmodifiableMap(Function<? super T, ? extends K> keyMapper,
    1496                                                 Function<? super T, ? extends U> valueMapper) {
    1497         Objects.requireNonNull(keyMapper, "keyMapper");
    1498         Objects.requireNonNull(valueMapper, "valueMapper");
    1499         return collectingAndThen(
    1500                 toMap(keyMapper, valueMapper),
    1501                 map -> (Map<K,U>)Map.ofEntries(map.entrySet().toArray(new Map.Entry[0])));
    1502     }
    1503
    1504     /**
    1505      * Returns a {@code Collector} that accumulates elements into a
    1506      * {@code Map} whose keys and values are the result of applying the provided
    1507      * mapping functions to the input elements.
    1508      *
    1509      * <p>If the mapped
    1510      * keys contain duplicates (according to {@link Object#equals(Object)}),
    1511      * the value mapping function is applied to each equal element, and the
    1512      * results are merged using the provided merging function.
    1513      *
    1514      * <p>There are no guarantees on the type, mutability, serializability,
    1515      * or thread-safety of the {@code Map} returned.
    1516      *
    1517      * @apiNote
    1518      * There are multiple ways to deal with collisions between multiple elements
    1519      * mapping to the same key.  The other forms of {@code toMap} simply use
    1520      * a merge function that throws unconditionally, but you can easily write
    1521      * more flexible merge policies.  For example, if you have a stream
    1522      * of {@code Person}, and you want to produce a "phone book" mapping name to
    1523      * address, but it is possible that two persons have the same name, you can
    1524      * do as follows to gracefully deal with these collisions, and produce a
    1547      * @param mergeFunction a merge function, used to resolve collisions between
    1548      *                      values associated with the same key, as supplied
    1549      *                      to {@link Map#merge(Object, Object, BiFunction)}
    1550      * @return a {@code Collector} which collects elements into a {@code Map}
    1551      * whose keys are the result of applying a key mapping function to the input
    1552      * elements, and whose values are the result of applying a value mapping
    1553      * function to all input elements equal to the key and combining them
    1554      * using the merge function
    1555      *
    1556      * @see #toMap(Function, Function)
    1557      * @see #toMap(Function, Function, BinaryOperator, Supplier)
    1558      * @see #toConcurrentMap(Function, Function, BinaryOperator)
    1559      */
    1560     public static <T, K, U>
    1561     Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
    1562                                     Function<? super T, ? extends U> valueMapper,
    1563                                     BinaryOperator<U> mergeFunction) {
    1564         return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);
    1565     }
    1566
    1567
    1568     /**
    1569      * Returns a {@code Collector} that accumulates the input elements into an
    1570      * <a href="../Map.html#unmodifiable">unmodifiable Map</a>,
    1571      * whose keys and values are the result of applying the provided
    1572      * mapping functions to the input elements.
    1573      *
    1574      * <p>If the mapped
    1575      * keys contain duplicates (according to {@link Object#equals(Object)}),
    1576      * the value mapping function is applied to each equal element, and the
    1577      * results are merged using the provided merging function.
    1578      *
    1579      * <p>The returned Collector disallows null keys and values. If either mapping function
    1580      * returns null, {@code NullPointerException} will be thrown.
    1581      *
    1582      * @param <T> the type of the input elements
    1583      * @param <K> the output type of the key mapping function
    1584      * @param <U> the output type of the value mapping function
    1585      * @param keyMapper a mapping function to produce keys, must be non-null
    1586      * @param valueMapper a mapping function to produce values, must be non-null
    1587      * @param mergeFunction a merge function, used to resolve collisions between
    1588      *                      values associated with the same key, as supplied
    1589      *                      to {@link Map#merge(Object, Object, BiFunction)},
    1590      *                      must be non-null
    1591      * @return a {@code Collector} that accumulates the input elements into an
    1592      * <a href="../Map.html#unmodifiable">unmodifiable Map</a>, whose keys and values
    1593      * are the result of applying the provided mapping functions to the input elements
    1594      * @throws NullPointerException if the keyMapper, valueMapper, or mergeFunction is null
    1595      *
    1596      * @see #toUnmodifiableMap(Function, Function)
    1597      * @since 10
    1598      */
    1599     @SuppressWarnings({"rawtypes", "unchecked"})
    1600     public static <T, K, U>
    1601     Collector<T, ?, Map<K,U>> toUnmodifiableMap(Function<? super T, ? extends K> keyMapper,
    1602                                                 Function<? super T, ? extends U> valueMapper,
    1603                                                 BinaryOperator<U> mergeFunction) {
    1604         Objects.requireNonNull(keyMapper, "keyMapper");
    1605         Objects.requireNonNull(valueMapper, "valueMapper");
    1606         Objects.requireNonNull(mergeFunction, "mergeFunction");
    1607         return collectingAndThen(
    1608                 toMap(keyMapper, valueMapper, mergeFunction, HashMap::new),
    1609                 map -> (Map<K,U>)Map.ofEntries(map.entrySet().toArray(new Map.Entry[0])));
    1610     }
    1611
    1612     /**
    1613      * Returns a {@code Collector} that accumulates elements into a
    1614      * {@code Map} whose keys and values are the result of applying the provided
    1615      * mapping functions to the input elements.
    1616      *
    1617      * <p>If the mapped
    1618      * keys contain duplicates (according to {@link Object#equals(Object)}),
    1619      * the value mapping function is applied to each equal element, and the
    1620      * results are merged using the provided merging function.  The {@code Map}
    1621      * is created by a provided supplier function.
    1622      *
    1623      * @implNote
    1624      * The returned {@code Collector} is not concurrent.  For parallel stream
    1625      * pipelines, the {@code combiner} function operates by merging the keys
    1626      * from one map into another, which can be an expensive operation.  If it is
    1627      * not required that results are merged into the {@code Map} in encounter
    1628      * order, using {@link #toConcurrentMap(Function, Function, BinaryOperator, Supplier)}
    1629      * may offer better parallel performance.
    1630      *
    1631      * @param <T> the type of the input elements

< prev index next >