< prev index next >

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

Print this page
rev 47479 : 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, 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} which collects all the input elements into a
 291      * {@code List}, 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} which collects all the input elements into a
 342      * {@code Set}
 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} which collects elements into an unmodifiable {@code Map}
1486      * whose keys and values are the result of applying mapping functions to
1487      * 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} which collects elements into an unmodifiable {@code Map}
1592      * whose keys are the result of applying a key mapping function to the input
1593      * elements, and whose values are the result of applying a value mapping
1594      * function to all input elements equal to the key and combining them
1595      * using the merge function
1596      * @throws NullPointerException if the keyMapper, valueMapper, or mergeFunction is null
1597      *
1598      * @see #toUnmodifiableMap(Function, Function)
1599      * @since 10
1600      */
1601     @SuppressWarnings({"rawtypes", "unchecked"})
1602     public static <T, K, U>
1603     Collector<T, ?, Map<K,U>> toUnmodifiableMap(Function<? super T, ? extends K> keyMapper,
1604                                                 Function<? super T, ? extends U> valueMapper,
1605                                                 BinaryOperator<U> mergeFunction) {
1606         Objects.requireNonNull(keyMapper, "keyMapper");
1607         Objects.requireNonNull(valueMapper, "valueMapper");
1608         Objects.requireNonNull(mergeFunction, "mergeFunction");
1609         return collectingAndThen(
1610                 toMap(keyMapper, valueMapper, mergeFunction, HashMap::new),
1611                 map -> (Map<K,U>)Map.ofEntries(map.entrySet().toArray(new Map.Entry[0])));
1612     }
1613 
1614     /**
1615      * Returns a {@code Collector} that accumulates elements into a
1616      * {@code Map} whose keys and values are the result of applying the provided
1617      * mapping functions to the input elements.
1618      *
1619      * <p>If the mapped
1620      * keys contain duplicates (according to {@link Object#equals(Object)}),
1621      * the value mapping function is applied to each equal element, and the
1622      * results are merged using the provided merging function.  The {@code Map}
1623      * is created by a provided supplier function.
1624      *
1625      * @implNote
1626      * The returned {@code Collector} is not concurrent.  For parallel stream
1627      * pipelines, the {@code combiner} function operates by merging the keys
1628      * from one map into another, which can be an expensive operation.  If it is
1629      * not required that results are merged into the {@code Map} in encounter
1630      * order, using {@link #toConcurrentMap(Function, Function, BinaryOperator, Supplier)}
1631      * may offer better parallel performance.
1632      *
1633      * @param <T> the type of the input elements


< prev index next >