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
|