< prev index next >

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

Print this page
rev 17661 : 8177290: add copy factory methods for unmodifiable List, Set, Map
8184690: add Collectors for collecting into unmodifiable List, Set, and Map
Reviewed-by: XXX


  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


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




  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</a> {@code List}.
 286      *
 287      * @param <T> the type of the input elements
 288      * @return a {@code Collector} which collects all the input elements into a
 289      * {@code List}, in encounter order
 290      * @since 10
 291      */
 292     @SuppressWarnings("unchecked")
 293     public static <T>
 294     Collector<T, ?, List<T>> toUnmodifiableList() {
 295         return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
 296                                    (left, right) -> { left.addAll(right); return left; },
 297                                    list -> (List<T>)List.of(list.toArray()),
 298                                    CH_NOID);
 299     }
 300 
 301     /**
 302      * Returns a {@code Collector} that accumulates the input elements into a
 303      * new {@code Set}. There are no guarantees on the type, mutability,
 304      * serializability, or thread-safety of the {@code Set} returned; if more
 305      * control over the returned {@code Set} is required, use
 306      * {@link #toCollection(Supplier)}.
 307      *
 308      * <p>This is an {@link Collector.Characteristics#UNORDERED unordered}
 309      * Collector.
 310      *
 311      * @param <T> the type of the input elements
 312      * @return a {@code Collector} which collects all the input elements into a
 313      * {@code Set}
 314      */
 315     public static <T>
 316     Collector<T, ?, Set<T>> toSet() {
 317         return new CollectorImpl<>((Supplier<Set<T>>) HashSet::new, Set::add,
 318                                    (left, right) -> {
 319                                        if (left.size() < right.size()) {
 320                                            right.addAll(left); return right;
 321                                        } else {
 322                                            left.addAll(right); return left;
 323                                        }
 324                                    },
 325                                    CH_UNORDERED_ID);
 326     }
 327 
 328     /**
 329      * Returns a {@code Collector} that accumulates the input elements into an
 330      * <a href="Set.html#unmodifiable">unmodifiable</a> {@code Set}.
 331      *
 332      * <p>This is an {@link Collector.Characteristics#UNORDERED unordered}
 333      * Collector.
 334      *
 335      * @param <T> the type of the input elements
 336      * @return a {@code Collector} which collects all the input elements into a
 337      * {@code Set}
 338      * @since 10
 339      */
 340     @SuppressWarnings("unchecked")
 341     public static <T>
 342     Collector<T, ?, Set<T>> toUnmodifiableSet() {
 343         return new CollectorImpl<>((Supplier<Set<T>>) HashSet::new, Set::add,
 344                                    (left, right) -> {
 345                                        if (left.size() < right.size()) {
 346                                            right.addAll(left); return right;
 347                                        } else {
 348                                            left.addAll(right); return left;
 349                                        }
 350                                    },
 351                                    set -> (Set<T>)Set.of(set.toArray()),
 352                                    CH_UNORDERED_NOID);
 353     }
 354 
 355     /**
 356      * Returns a {@code Collector} that concatenates the input elements into a
 357      * {@code String}, in encounter order.
 358      *
 359      * @return a {@code Collector} that concatenates the input elements into a
 360      * {@code String}, in encounter order
 361      */
 362     public static Collector<CharSequence, ?, String> joining() {
 363         return new CollectorImpl<CharSequence, StringBuilder, String>(
 364                 StringBuilder::new, StringBuilder::append,
 365                 (r1, r2) -> { r1.append(r2); return r1; },
 366                 StringBuilder::toString, CH_NOID);
 367     }
 368 
 369     /**
 370      * Returns a {@code Collector} that concatenates the input elements,
 371      * separated by the specified delimiter, in encounter order.
 372      *
 373      * @param delimiter the delimiter to be used between each element
 374      * @return A {@code Collector} which concatenates CharSequence elements,
 375      * separated by the specified delimiter, in encounter order


1441      * @param keyMapper a mapping function to produce keys
1442      * @param valueMapper a mapping function to produce values
1443      * @return a {@code Collector} which collects elements into a {@code Map}
1444      * whose keys and values are the result of applying mapping functions to
1445      * the input elements
1446      *
1447      * @see #toMap(Function, Function, BinaryOperator)
1448      * @see #toMap(Function, Function, BinaryOperator, Supplier)
1449      * @see #toConcurrentMap(Function, Function)
1450      */
1451     public static <T, K, U>
1452     Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
1453                                     Function<? super T, ? extends U> valueMapper) {
1454         return new CollectorImpl<>(HashMap::new,
1455                                    uniqKeysMapAccumulator(keyMapper, valueMapper),
1456                                    uniqKeysMapMerger(),
1457                                    CH_ID);
1458     }
1459 
1460     /**
1461      * Returns a {@code Collector} that accumulates the input elements into an
1462      * <a href="Map.html#unmodifiable">unmodifiable</a> {@code Map},
1463      * whose keys and values are the result of applying the provided
1464      * mapping functions to the input elements.
1465      *
1466      * <p>If the mapped keys contain duplicates (according to
1467      * {@link Object#equals(Object)}), an {@code IllegalStateException} is
1468      * thrown when the collection operation is performed.  If the mapped keys
1469      * may have duplicates, use {@link #toUnmodifiableMap(Function, Function, BinaryOperator)}
1470      * instead.
1471      *
1472      * @param <T> the type of the input elements
1473      * @param <K> the output type of the key mapping function
1474      * @param <U> the output type of the value mapping function
1475      * @param keyMapper a mapping function to produce keys
1476      * @param valueMapper a mapping function to produce values
1477      * @return a {@code Collector} which collects elements into an unmodifiable {@code Map}
1478      * whose keys and values are the result of applying mapping functions to
1479      * the input elements
1480      *
1481      * @see #toUnmodifiableMap(Function, Function, BinaryOperator)
1482      * @since 10
1483      */
1484     @SuppressWarnings({"rawtypes", "unchecked"})
1485     public static <T, K, U>
1486     Collector<T, ?, Map<K,U>> toUnmodifiableMap(Function<? super T, ? extends K> keyMapper,
1487                                                 Function<? super T, ? extends U> valueMapper) {
1488         return new CollectorImpl<>(() -> new ArrayList<Map.Entry<K, U>>(),
1489                                    (list, t) -> list.add(Map.entry(keyMapper.apply(t), valueMapper.apply(t))),
1490                                    (list1, list2) -> { list1.addAll(list2); return list1; },
1491                                    list -> (Map<K,U>)Map.ofEntries(list.toArray(new Map.Entry[0])),
1492                                    CH_UNORDERED_NOID);
1493     }
1494 
1495     /**
1496      * Returns a {@code Collector} that accumulates elements into a
1497      * {@code Map} whose keys and values are the result of applying the provided
1498      * mapping functions to the input elements.
1499      *
1500      * <p>If the mapped
1501      * keys contain duplicates (according to {@link Object#equals(Object)}),
1502      * the value mapping function is applied to each equal element, and the
1503      * results are merged using the provided merging function.
1504      *
1505      * <p>There are no guarantees on the type, mutability, serializability,
1506      * or thread-safety of the {@code Map} returned.
1507      *
1508      * @apiNote
1509      * There are multiple ways to deal with collisions between multiple elements
1510      * mapping to the same key.  The other forms of {@code toMap} simply use
1511      * a merge function that throws unconditionally, but you can easily write
1512      * more flexible merge policies.  For example, if you have a stream
1513      * of {@code Person}, and you want to produce a "phone book" mapping name to
1514      * address, but it is possible that two persons have the same name, you can
1515      * do as follows to gracefully deal with these collisions, and produce a


1538      * @param mergeFunction a merge function, used to resolve collisions between
1539      *                      values associated with the same key, as supplied
1540      *                      to {@link Map#merge(Object, Object, BiFunction)}
1541      * @return a {@code Collector} which collects elements into a {@code Map}
1542      * whose keys are the result of applying a key mapping function to the input
1543      * elements, and whose values are the result of applying a value mapping
1544      * function to all input elements equal to the key and combining them
1545      * using the merge function
1546      *
1547      * @see #toMap(Function, Function)
1548      * @see #toMap(Function, Function, BinaryOperator, Supplier)
1549      * @see #toConcurrentMap(Function, Function, BinaryOperator)
1550      */
1551     public static <T, K, U>
1552     Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
1553                                     Function<? super T, ? extends U> valueMapper,
1554                                     BinaryOperator<U> mergeFunction) {
1555         return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);
1556     }
1557 
1558 
1559     /**
1560      * Returns a {@code Collector} that accumulates the input elements into an
1561      * <a href="Map.html#unmodifiable">unmodifiable</a> {@code Map},
1562      * whose keys and values are the result of applying the provided
1563      * mapping functions to the input elements.
1564      *
1565      * <p>If the mapped
1566      * keys contain duplicates (according to {@link Object#equals(Object)}),
1567      * the value mapping function is applied to each equal element, and the
1568      * results are merged using the provided merging function.
1569      *
1570      * @param <T> the type of the input elements
1571      * @param <K> the output type of the key mapping function
1572      * @param <U> the output type of the value mapping function
1573      * @param keyMapper a mapping function to produce keys
1574      * @param valueMapper a mapping function to produce values
1575      * @param mergeFunction a merge function, used to resolve collisions between
1576      *                      values associated with the same key, as supplied
1577      *                      to {@link Map#merge(Object, Object, BiFunction)}
1578      * @return a {@code Collector} which collects elements into an unmodifiable {@code Map}
1579      * whose keys are the result of applying a key mapping function to the input
1580      * elements, and whose values are the result of applying a value mapping
1581      * function to all input elements equal to the key and combining them
1582      * using the merge function
1583      *
1584      * @see #toUnmodifiableMap(Function, Function)
1585      * @since 10
1586      */
1587     @SuppressWarnings({"rawtypes", "unchecked"})
1588     public static <T, K, U>
1589     Collector<T, ?, Map<K,U>> toUnmodifiableMap(Function<? super T, ? extends K> keyMapper,
1590                                                 Function<? super T, ? extends U> valueMapper,
1591                                                 BinaryOperator<U> mergeFunction) {
1592         return collectingAndThen(
1593                 toMap(keyMapper, valueMapper, mergeFunction, HashMap::new),
1594                 hm -> (Map<K,U>)Map.ofEntries(hm.entrySet().toArray(new Map.Entry[0])));
1595     }
1596 
1597     /**
1598      * Returns a {@code Collector} that accumulates elements into a
1599      * {@code Map} whose keys and values are the result of applying the provided
1600      * mapping functions to the input elements.
1601      *
1602      * <p>If the mapped
1603      * keys contain duplicates (according to {@link Object#equals(Object)}),
1604      * the value mapping function is applied to each equal element, and the
1605      * results are merged using the provided merging function.  The {@code Map}
1606      * is created by a provided supplier function.
1607      *
1608      * @implNote
1609      * The returned {@code Collector} is not concurrent.  For parallel stream
1610      * pipelines, the {@code combiner} function operates by merging the keys
1611      * from one map into another, which can be an expensive operation.  If it is
1612      * not required that results are merged into the {@code Map} in encounter
1613      * order, using {@link #toConcurrentMap(Function, Function, BinaryOperator, Supplier)}
1614      * may offer better parallel performance.
1615      *
1616      * @param <T> the type of the input elements


< prev index next >