1 /* 2 * Copyright (c) 2012, 2013, 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 23 * questions. 24 */ 25 package java.util.stream; 26 27 import java.util.AbstractMap; 28 import java.util.AbstractSet; 29 import java.util.ArrayList; 30 import java.util.Collection; 31 import java.util.Collections; 32 import java.util.Comparator; 33 import java.util.DoubleSummaryStatistics; 34 import java.util.EnumSet; 35 import java.util.HashMap; 36 import java.util.HashSet; 37 import java.util.IntSummaryStatistics; 38 import java.util.Iterator; 39 import java.util.List; 40 import java.util.LongSummaryStatistics; 41 import java.util.Map; 42 import java.util.NoSuchElementException; 43 import java.util.Objects; 44 import java.util.Set; 45 import java.util.StringJoiner; 46 import java.util.concurrent.ConcurrentHashMap; 47 import java.util.concurrent.ConcurrentMap; 48 import java.util.function.BiFunction; 49 import java.util.function.BinaryOperator; 50 import java.util.function.Function; 51 import java.util.function.Predicate; 52 import java.util.function.Supplier; 53 import java.util.function.ToDoubleFunction; 54 import java.util.function.ToIntFunction; 55 import java.util.function.ToLongFunction; 56 57 /** 58 * Implementations of {@link Collector} that implement various useful reduction 59 * operations, such as accumulating elements into collections, summarizing 60 * elements according to various criteria, etc. 61 * 62 * <p>The following are examples of using the predefined {@code Collector} 63 * implementations in {@link Collectors} with the {@code Stream} API to perform 64 * mutable reduction tasks: 65 * 66 * <pre>{@code 67 * // Accumulate elements into a List 68 * List<Person> list = people.collect(Collectors.toList()); 69 * 70 * // Accumulate elements into a TreeSet 71 * List<Person> list = people.collect(Collectors.toCollection(TreeSet::new)); 72 * 73 * // Convert elements to strings and concatenate them, separated by commas 74 * String joined = stream.map(Object::toString) 75 * .collect(Collectors.toStringJoiner(", ")) 76 * .toString(); 77 * 78 * // Find highest-paid employee 79 * Employee highestPaid = employees.stream() 80 * .collect(Collectors.maxBy(Comparator.comparing(Employee::getSalary))); 81 * 82 * // Group employees by department 83 * Map<Department, List<Employee>> byDept 84 * = employees.stream() 85 * .collect(Collectors.groupingBy(Employee::getDepartment)); 86 * 87 * // Find highest-paid employee by department 88 * Map<Department, Employee> highestPaidByDept 89 * = employees.stream() 90 * .collect(Collectors.groupingBy(Employee::getDepartment, 91 * Collectors.maxBy(Comparator.comparing(Employee::getSalary)))); 92 * 93 * // Partition students into passing and failing 94 * Map<Boolean, List<Student>> passingFailing = 95 * students.stream() 96 * .collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD); 97 * 98 * }</pre> 99 * 100 * TODO explanation of parallel collection 101 * 102 * @since 1.8 103 */ 104 public final class Collectors { 105 106 private static final Set<Collector.Characteristics> CH_CONCURRENT 107 = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.CONCURRENT, 108 Collector.Characteristics.STRICTLY_MUTATIVE, 109 Collector.Characteristics.UNORDERED)); 110 private static final Set<Collector.Characteristics> CH_STRICT 111 = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.STRICTLY_MUTATIVE)); 112 private static final Set<Collector.Characteristics> CH_STRICT_UNORDERED 113 = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.STRICTLY_MUTATIVE, 114 Collector.Characteristics.UNORDERED)); 115 116 private Collectors() { } 117 118 /** 119 * Returns a merge function, suitable for use in 120 * {@link Map#merge(Object, Object, BiFunction) Map.merge()} or 121 * {@link #toMap(Function, Function, BinaryOperator) toMap()}, which always 122 * throws {@code IllegalStateException}. This can be used to enforce the 123 * assumption that the elements being collected are distinct. 124 * 125 * @param <T> the type of input arguments to the merge function 126 * @return a merge function which always throw {@code IllegalStateException} 127 * 128 * @see #firstWinsMerger() 129 * @see #lastWinsMerger() 130 */ 131 public static <T> BinaryOperator<T> throwingMerger() { 132 return (u,v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); }; 133 } 134 135 /** 136 * Returns a merge function, suitable for use in 137 * {@link Map#merge(Object, Object, BiFunction) Map.merge()} or 138 * {@link #toMap(Function, Function, BinaryOperator) toMap()}, 139 * which implements a "first wins" policy. 140 * 141 * @param <T> the type of input arguments to the merge function 142 * @return a merge function which always returns its first argument 143 * @see #lastWinsMerger() 144 * @see #throwingMerger() 145 */ 146 public static <T> BinaryOperator<T> firstWinsMerger() { 147 return (u,v) -> u; 148 } 149 150 /** 151 * Returns a merge function, suitable for use in 152 * {@link Map#merge(Object, Object, BiFunction) Map.merge()} or 153 * {@link #toMap(Function, Function, BinaryOperator) toMap()}, 154 * which implements a "last wins" policy. 155 * 156 * @param <T> the type of input arguments to the merge function 157 * @return a merge function which always returns its second argument 158 * @see #firstWinsMerger() 159 * @see #throwingMerger() 160 */ 161 public static <T> BinaryOperator<T> lastWinsMerger() { 162 return (u,v) -> v; 163 } 164 165 /** 166 * Simple implementation class for {@code Collector}. 167 * 168 * @param <T> the type of elements to be collected 169 * @param <R> the type of the result 170 */ 171 private static final class CollectorImpl<T, R> implements Collector<T,R> { 172 private final Supplier<R> resultSupplier; 173 private final BiFunction<R, T, R> accumulator; 174 private final BinaryOperator<R> combiner; 175 private final Set<Characteristics> characteristics; 176 177 CollectorImpl(Supplier<R> resultSupplier, 178 BiFunction<R, T, R> accumulator, 179 BinaryOperator<R> combiner, 180 Set<Characteristics> characteristics) { 181 this.resultSupplier = resultSupplier; 182 this.accumulator = accumulator; 183 this.combiner = combiner; 184 this.characteristics = characteristics; 185 } 186 187 CollectorImpl(Supplier<R> resultSupplier, 188 BiFunction<R, T, R> accumulator, 189 BinaryOperator<R> combiner) { 190 this(resultSupplier, accumulator, combiner, Collections.emptySet()); 191 } 192 193 @Override 194 public BiFunction<R, T, R> accumulator() { 195 return accumulator; 196 } 197 198 @Override 199 public Supplier<R> resultSupplier() { 200 return resultSupplier; 201 } 202 203 @Override 204 public BinaryOperator<R> combiner() { 205 return combiner; 206 } 207 208 @Override 209 public Set<Characteristics> characteristics() { 210 return characteristics; 211 } 212 } 213 214 /** 215 * Returns a {@code Collector} that accumulates the input elements into a 216 * new {@code Collection}, in encounter order. The {@code Collection} is 217 * created by the provided factory. 218 * 219 * @param <T> the type of the input elements 220 * @param <C> the type of the resulting {@code Collection} 221 * @param collectionFactory a {@code Supplier} which returns a new, empty 222 * {@code Collection} of the appropriate type 223 * @return a {@code Collector} which collects all the input elements into a 224 * {@code Collection}, in encounter order 225 */ 226 public static <T, C extends Collection<T>> 227 Collector<T, C> toCollection(Supplier<C> collectionFactory) { 228 return new CollectorImpl<>(collectionFactory, 229 (r, t) -> { r.add(t); return r; }, 230 (r1, r2) -> { r1.addAll(r2); return r1; }, 231 CH_STRICT); 232 } 233 234 /** 235 * Returns a {@code Collector} that accumulates the input elements into a 236 * new {@code List}. There are no guarantees on the type, mutability, 237 * serializability, or thread-safety of the {@code List} returned. 238 * 239 * @param <T> the type of the input elements 240 * @return a {@code Collector} which collects all the input elements into a 241 * {@code List}, in encounter order 242 */ 243 public static <T> 244 Collector<T, List<T>> toList() { 245 BiFunction<List<T>, T, List<T>> accumulator = (list, t) -> { 246 switch (list.size()) { 247 case 0: 248 return Collections.singletonList(t); 249 case 1: 250 List<T> newList = new ArrayList<>(); 251 newList.add(list.get(0)); 252 newList.add(t); 253 return newList; 254 default: 255 list.add(t); 256 return list; 257 } 258 }; 259 BinaryOperator<List<T>> combiner = (left, right) -> { 260 switch (left.size()) { 261 case 0: 262 return right; 263 case 1: 264 List<T> newList = new ArrayList<>(left.size() + right.size()); 265 newList.addAll(left); 266 newList.addAll(right); 267 return newList; 268 default: 269 left.addAll(right); 270 return left; 271 } 272 }; 273 return new CollectorImpl<>(Collections::emptyList, accumulator, combiner); 274 } 275 276 /** 277 * Returns a {@code Collector} that accumulates the input elements into a 278 * new {@code Set}. There are no guarantees on the type, mutability, 279 * serializability, or thread-safety of the {@code Set} returned. 280 * 281 * <p>This is an {@link Collector.Characteristics#UNORDERED unordered} 282 * Collector. 283 * 284 * @param <T> the type of the input elements 285 * @return a {@code Collector} which collects all the input elements into a 286 * {@code Set} 287 */ 288 public static <T> 289 Collector<T, Set<T>> toSet() { 290 return new CollectorImpl<>((Supplier<Set<T>>) HashSet::new, 291 (r, t) -> { r.add(t); return r; }, 292 (r1, r2) -> { r1.addAll(r2); return r1; }, 293 CH_STRICT_UNORDERED); 294 } 295 296 /** 297 * Returns a {@code Collector} that concatenates the input elements into a 298 * new {@link StringBuilder}. 299 * 300 * @return a {@code Collector} which collects String elements into a 301 * {@code StringBuilder}, in encounter order 302 */ 303 public static Collector<String, StringBuilder> toStringBuilder() { 304 return new CollectorImpl<>(StringBuilder::new, 305 (r, t) -> { r.append(t); return r; }, 306 (r1, r2) -> { r1.append(r2); return r1; }, 307 CH_STRICT); 308 } 309 310 /** 311 * Returns a {@code Collector} that concatenates the input elements into a 312 * new {@link StringJoiner}, using the specified delimiter. 313 * 314 * @param delimiter the delimiter to be used between each element 315 * @return A {@code Collector} which collects String elements into a 316 * {@code StringJoiner}, in encounter order 317 */ 318 public static Collector<CharSequence, StringJoiner> toStringJoiner(CharSequence delimiter) { 319 BinaryOperator<StringJoiner> merger = (sj, other) -> { 320 if (other.length() > 0) 321 sj.add(other.toString()); 322 return sj; 323 }; 324 return new CollectorImpl<>(() -> new StringJoiner(delimiter), 325 (r, t) -> { r.add(t); return r; }, 326 merger, CH_STRICT); 327 } 328 329 /** 330 * {@code BinaryOperator<Map>} that merges the contents of its right 331 * argument into its left argument, using the provided merge function to 332 * handle duplicate keys. 333 * 334 * @param <K> type of the map keys 335 * @param <V> type of the map values 336 * @param <M> type of the map 337 * @param mergeFunction A merge function suitable for 338 * {@link Map#merge(Object, Object, BiFunction) Map.merge()} 339 * @return a merge function for two maps 340 */ 341 private static <K, V, M extends Map<K,V>> 342 BinaryOperator<M> mapMerger(BinaryOperator<V> mergeFunction) { 343 return (m1, m2) -> { 344 for (Map.Entry<K,V> e : m2.entrySet()) 345 m1.merge(e.getKey(), e.getValue(), mergeFunction); 346 return m1; 347 }; 348 } 349 350 /** 351 * Adapts a {@code Collector<U,R>} to a {@code Collector<T,R>} by applying 352 * a mapping function to each input element before accumulation. 353 * 354 * @apiNote 355 * The {@code mapping()} collectors are most useful when used in a 356 * multi-level reduction, downstream of {@code groupingBy} or 357 * {@code partitioningBy}. For example, given a stream of 358 * {@code Person}, to accumulate the set of last names in each city: 359 * <pre>{@code 360 * Map<City, Set<String>> lastNamesByCity 361 * = people.stream().collect(groupingBy(Person::getCity, 362 * mapping(Person::getLastName, toSet()))); 363 * }</pre> 364 * 365 * @param <T> the type of the input elements 366 * @param <U> type of elements accepted by downstream collector 367 * @param <R> result type of collector 368 * @param mapper a function to be applied to the input elements 369 * @param downstream a collector which will accept mapped values 370 * @return a collector which applies the mapping function to the input 371 * elements and provides the mapped results to the downstream collector 372 */ 373 public static <T, U, R> Collector<T, R> 374 mapping(Function<? super T, ? extends U> mapper, Collector<? super U, R> downstream) { 375 BiFunction<R, ? super U, R> downstreamAccumulator = downstream.accumulator(); 376 return new CollectorImpl<>(downstream.resultSupplier(), 377 (r, t) -> downstreamAccumulator.apply(r, mapper.apply(t)), 378 downstream.combiner(), downstream.characteristics()); 379 } 380 381 /** 382 * Returns a {@code Collector<T, Long>} that counts the number of input 383 * elements. 384 * 385 * @implSpec 386 * This produces a result equivalent to: 387 * <pre>{@code 388 * reducing(0L, e -> 1L, Long::sum) 389 * }</pre> 390 * 391 * @param <T> the type of the input elements 392 * @return a {@code Collector} that counts the input elements 393 */ 394 public static <T> Collector<T, Long> 395 counting() { 396 return reducing(0L, e -> 1L, Long::sum); 397 } 398 399 /** 400 * Returns a {@code Collector<T, T>} that produces the minimal element 401 * according to a given {@code Comparator}. 402 * 403 * @implSpec 404 * This produces a result equivalent to: 405 * <pre>{@code 406 * reducing(BinaryOperator.minBy(comparator)) 407 * }</pre> 408 * 409 * @param <T> the type of the input elements 410 * @param comparator a {@code Comparator} for comparing elements 411 * @return a {@code Collector} that produces the minimal value 412 */ 413 public static <T> Collector<T, T> 414 minBy(Comparator<? super T> comparator) { 415 return reducing(BinaryOperator.minBy(comparator)); 416 } 417 418 /** 419 * Returns a {@code Collector<T, T>} that produces the maximal element 420 * according to a given {@code Comparator}. 421 * 422 * @implSpec 423 * This produces a result equivalent to: 424 * <pre>{@code 425 * reducing(BinaryOperator.maxBy(comparator)) 426 * }</pre> 427 * 428 * @param <T> the type of the input elements 429 * @param comparator a {@code Comparator} for comparing elements 430 * @return a {@code Collector} that produces the maximal value 431 */ 432 public static <T> Collector<T, T> 433 maxBy(Comparator<? super T> comparator) { 434 return reducing(BinaryOperator.maxBy(comparator)); 435 } 436 437 /** 438 * Returns a {@code Collector<T, Long>} that produces the sum of a 439 * long-valued function applied to the input element. 440 * 441 * @implSpec 442 * This produces a result equivalent to: 443 * <pre>{@code 444 * reducing(0L, mapper, Long::sum) 445 * }</pre> 446 * 447 * @param <T> the type of the input elements 448 * @param mapper a function extracting the property to be summed 449 * @return a {@code Collector} that produces the sum of a derived property 450 */ 451 public static <T> Collector<T, Long> 452 sumBy(Function<? super T, Long> mapper) { 453 return reducing(0L, mapper, Long::sum); 454 } 455 456 /** 457 * Returns a {@code Collector<T,T>} which performs a reduction of its 458 * input elements under a specified {@code BinaryOperator}. 459 * 460 * @apiNote 461 * The {@code reducing()} collectors are most useful when used in a 462 * multi-level reduction, downstream of {@code groupingBy} or 463 * {@code partitioningBy}. To perform a simple reduction on a stream, 464 * use {@link Stream#reduce(BinaryOperator)} instead. 465 * 466 * @param <T> element type for the input and output of the reduction 467 * @param identity the identity value for the reduction (also, the value 468 * that is returned when there are no input elements) 469 * @param op a {@code BinaryOperator<T>} used to reduce the input elements 470 * @return a {@code Collector} which implements the reduction operation 471 * 472 * @see #reducing(BinaryOperator) 473 * @see #reducing(Object, Function, BinaryOperator) 474 */ 475 public static <T> Collector<T, T> 476 reducing(T identity, BinaryOperator<T> op) { 477 return new CollectorImpl<>(() -> identity, (r, t) -> (r == null ? t : op.apply(r, t)), op); 478 } 479 480 /** 481 * Returns a {@code Collector<T,T>} which performs a reduction of its 482 * input elements under a specified {@code BinaryOperator}. 483 * 484 * @apiNote 485 * The {@code reducing()} collectors are most useful when used in a 486 * multi-level reduction, downstream of {@code groupingBy} or 487 * {@code partitioningBy}. To perform a simple reduction on a stream, 488 * use {@link Stream#reduce(BinaryOperator)} instead. 489 * 490 * <p>For example, given a stream of {@code Person}, to calculate tallest 491 * person in each city: 492 * <pre>{@code 493 * Comparator<Person> byHeight = Comparator.comparing(Person::getHeight); 494 * BinaryOperator<Person> tallerOf = BinaryOperator.greaterOf(byHeight); 495 * Map<City, Person> tallestByCity 496 * = people.stream().collect(groupingBy(Person::getCity, reducing(tallerOf))); 497 * }</pre> 498 * 499 * @implSpec 500 * The default implementation is equivalent to: 501 * <pre>{@code 502 * reducing(null, op); 503 * }</pre> 504 * 505 * @param <T> element type for the input and output of the reduction 506 * @param op a {@code BinaryOperator<T>} used to reduce the input elements 507 * @return a {@code Collector} which implements the reduction operation 508 * 509 * @see #reducing(Object, BinaryOperator) 510 * @see #reducing(Object, Function, BinaryOperator) 511 */ 512 public static <T> Collector<T, T> 513 reducing(BinaryOperator<T> op) { 514 return reducing(null, op); 515 } 516 517 /** 518 * Returns a {@code Collector<T,U>} which performs a reduction of its 519 * input elements under a specified mapping function and 520 * {@code BinaryOperator}. This is a generalization of 521 * {@link #reducing(Object, BinaryOperator)} which allows a transformation 522 * of the elements before reduction. 523 * 524 * @apiNote 525 * The {@code reducing()} collectors are most useful when used in a 526 * multi-level reduction, downstream of {@code groupingBy} or 527 * {@code partitioningBy}. To perform a simple reduction on a stream, 528 * use {@link Stream#reduce(BinaryOperator)} instead. 529 * 530 * <p>For example, given a stream of {@code Person}, to calculate the longest 531 * last name of residents in each city: 532 * <pre>{@code 533 * Comparator<String> byLength = Comparator.comparing(String::length); 534 * BinaryOperator<String> longerOf = BinaryOperator.greaterOf(byLength); 535 * Map<City, String> longestLastNameByCity 536 * = people.stream().collect(groupingBy(Person::getCity, 537 * reducing(Person::getLastName, longerOf))); 538 * }</pre> 539 * 540 * @param <T> the type of the input elements 541 * @param <U> the type of the mapped values 542 * @param identity the identity value for the reduction (also, the value 543 * that is returned when there are no input elements) 544 * @param mapper a mapping function to apply to each input value 545 * @param op a {@code BinaryOperator<U>} used to reduce the mapped values 546 * @return a {@code Collector} implementing the map-reduce operation 547 * 548 * @see #reducing(Object, BinaryOperator) 549 * @see #reducing(BinaryOperator) 550 */ 551 public static <T, U> 552 Collector<T, U> reducing(U identity, 553 Function<? super T, ? extends U> mapper, 554 BinaryOperator<U> op) { 555 return new CollectorImpl<>(() -> identity, 556 (r, t) -> (r == null ? mapper.apply(t) : op.apply(r, mapper.apply(t))), 557 op); 558 } 559 560 /** 561 * Returns a {@code Collector} implementing a "group by" operation on 562 * input elements of type {@code T}, grouping elements according to a 563 * classification function. 564 * 565 * <p>The classification function maps elements to some key type {@code K}. 566 * The collector produces a {@code Map<K, List<T>>} whose keys are the 567 * values resulting from applying the classification function to the input 568 * elements, and whose corresponding values are {@code List}s containing the 569 * input elements which map to the associated key under the classification 570 * function. 571 * 572 * <p>There are no guarantees on the type, mutability, serializability, or 573 * thread-safety of the {@code Map} or {@code List} objects returned. 574 * @implSpec 575 * This produces a result similar to: 576 * <pre>{@code 577 * groupingBy(classifier, toList()); 578 * }</pre> 579 * 580 * @param <T> the type of the input elements 581 * @param <K> the type of the keys 582 * @param classifier the classifier function mapping input elements to keys 583 * @return a {@code Collector} implementing the group-by operation 584 * 585 * @see #groupingBy(Function, Collector) 586 * @see #groupingBy(Function, Supplier, Collector) 587 * @see #groupingByConcurrent(Function) 588 */ 589 public static <T, K> 590 Collector<T, Map<K, List<T>>> groupingBy(Function<? super T, ? extends K> classifier) { 591 return groupingBy(classifier, HashMap::new, toList()); 592 } 593 594 /** 595 * Returns a {@code Collector} implementing a cascaded "group by" operation 596 * on input elements of type {@code T}, grouping elements according to a 597 * classification function, and then performing a reduction operation on 598 * the values associated with a given key using the specified downstream 599 * {@code Collector}. 600 * 601 * <p>The classification function maps elements to some key type {@code K}. 602 * The downstream collector operates on elements of type {@code T} and 603 * produces a result of type {@code D}. The resulting collector produces a 604 * {@code Map<K, D>}. 605 * 606 * <p>There are no guarantees on the type, mutability, 607 * serializability, or thread-safety of the {@code Map} returned. 608 * 609 * <p>For example, to compute the set of last names of people in each city: 610 * <pre>{@code 611 * Map<City, Set<String>> namesByCity 612 * = people.stream().collect(groupingBy(Person::getCity, 613 * mapping(Person::getLastName, toSet()))); 614 * }</pre> 615 * 616 * @param <T> the type of the input elements 617 * @param <K> the type of the keys 618 * @param <D> the result type of the downstream reduction 619 * @param classifier a classifier function mapping input elements to keys 620 * @param downstream a {@code Collector} implementing the downstream reduction 621 * @return a {@code Collector} implementing the cascaded group-by operation 622 * @see #groupingBy(Function) 623 * 624 * @see #groupingBy(Function, Supplier, Collector) 625 * @see #groupingByConcurrent(Function, Collector) 626 */ 627 public static <T, K, D> 628 Collector<T, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier, 629 Collector<? super T, D> downstream) { 630 return groupingBy(classifier, HashMap::new, downstream); 631 } 632 633 /** 634 * Returns a {@code Collector} implementing a cascaded "group by" operation 635 * on input elements of type {@code T}, grouping elements according to a 636 * classification function, and then performing a reduction operation on 637 * the values associated with a given key using the specified downstream 638 * {@code Collector}. The {@code Map} produced by the Collector is created 639 * with the supplied factory function. 640 * 641 * <p>The classification function maps elements to some key type {@code K}. 642 * The downstream collector operates on elements of type {@code T} and 643 * produces a result of type {@code D}. The resulting collector produces a 644 * {@code Map<K, D>}. 645 * 646 * <p>For example, to compute the set of last names of people in each city, 647 * where the city names are sorted: 648 * <pre>{@code 649 * Map<City, Set<String>> namesByCity 650 * = people.stream().collect(groupingBy(Person::getCity, TreeMap::new, 651 * mapping(Person::getLastName, toSet()))); 652 * }</pre> 653 * 654 * @param <T> the type of the input elements 655 * @param <K> the type of the keys 656 * @param <D> the result type of the downstream reduction 657 * @param <M> the type of the resulting {@code Map} 658 * @param classifier a classifier function mapping input elements to keys 659 * @param downstream a {@code Collector} implementing the downstream reduction 660 * @param mapFactory a function which, when called, produces a new empty 661 * {@code Map} of the desired type 662 * @return a {@code Collector} implementing the cascaded group-by operation 663 * 664 * @see #groupingBy(Function, Collector) 665 * @see #groupingBy(Function) 666 * @see #groupingByConcurrent(Function, Supplier, Collector) 667 */ 668 public static <T, K, D, M extends Map<K, D>> 669 Collector<T, M> groupingBy(Function<? super T, ? extends K> classifier, 670 Supplier<M> mapFactory, 671 Collector<? super T, D> downstream) { 672 Supplier<D> downstreamSupplier = downstream.resultSupplier(); 673 BiFunction<D, ? super T, D> downstreamAccumulator = downstream.accumulator(); 674 BiFunction<M, T, M> accumulator = (m, t) -> { 675 K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key"); 676 D oldContainer = m.computeIfAbsent(key, k -> downstreamSupplier.get()); 677 D newContainer = downstreamAccumulator.apply(oldContainer, t); 678 if (newContainer != oldContainer) 679 m.put(key, newContainer); 680 return m; 681 }; 682 return new CollectorImpl<>(mapFactory, accumulator, mapMerger(downstream.combiner()), CH_STRICT); 683 } 684 685 /** 686 * Returns a {@code Collector} implementing a concurrent "group by" 687 * operation on input elements of type {@code T}, grouping elements 688 * according to a classification function. 689 * 690 * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and 691 * {@link Collector.Characteristics#UNORDERED unordered} Collector. 692 * 693 * <p>The classification function maps elements to some key type {@code K}. 694 * The collector produces a {@code ConcurrentMap<K, List<T>>} whose keys are the 695 * values resulting from applying the classification function to the input 696 * elements, and whose corresponding values are {@code List}s containing the 697 * input elements which map to the associated key under the classification 698 * function. 699 * 700 * <p>There are no guarantees on the type, mutability, or serializability 701 * of the {@code Map} or {@code List} objects returned, or of the 702 * thread-safety of the {@code List} objects returned. 703 * @implSpec 704 * This produces a result similar to: 705 * <pre>{@code 706 * groupingByConcurrent(classifier, toList()); 707 * }</pre> 708 * 709 * @param <T> the type of the input elements 710 * @param <K> the type of the keys 711 * @param classifier a classifier function mapping input elements to keys 712 * @return a {@code Collector} implementing the group-by operation 713 * 714 * @see #groupingBy(Function) 715 * @see #groupingByConcurrent(Function, Collector) 716 * @see #groupingByConcurrent(Function, Supplier, Collector) 717 */ 718 public static <T, K> 719 Collector<T, ConcurrentMap<K, List<T>>> groupingByConcurrent(Function<? super T, ? extends K> classifier) { 720 return groupingByConcurrent(classifier, ConcurrentHashMap::new, toList()); 721 } 722 723 /** 724 * Returns a {@code Collector} implementing a concurrent cascaded "group by" 725 * operation on input elements of type {@code T}, grouping elements 726 * according to a classification function, and then performing a reduction 727 * operation on the values associated with a given key using the specified 728 * downstream {@code Collector}. 729 * 730 * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and 731 * {@link Collector.Characteristics#UNORDERED unordered} Collector. 732 * 733 * <p>The classification function maps elements to some key type {@code K}. 734 * The downstream collector operates on elements of type {@code T} and 735 * produces a result of type {@code D}. The resulting collector produces a 736 * {@code Map<K, D>}. 737 * 738 * <p>For example, to compute the set of last names of people in each city, 739 * where the city names are sorted: 740 * <pre>{@code 741 * ConcurrentMap<City, Set<String>> namesByCity 742 * = people.stream().collect(groupingByConcurrent(Person::getCity, TreeMap::new, 743 * mapping(Person::getLastName, toSet()))); 744 * }</pre> 745 * 746 * @param <T> the type of the input elements 747 * @param <K> the type of the keys 748 * @param <D> the result type of the downstream reduction 749 * @param classifier a classifier function mapping input elements to keys 750 * @param downstream a {@code Collector} implementing the downstream reduction 751 * @return a {@code Collector} implementing the cascaded group-by operation 752 * 753 * @see #groupingBy(Function, Collector) 754 * @see #groupingByConcurrent(Function) 755 * @see #groupingByConcurrent(Function, Supplier, Collector) 756 */ 757 public static <T, K, D> 758 Collector<T, ConcurrentMap<K, D>> groupingByConcurrent(Function<? super T, ? extends K> classifier, 759 Collector<? super T, D> downstream) { 760 return groupingByConcurrent(classifier, ConcurrentHashMap::new, downstream); 761 } 762 763 /** 764 * Returns a concurrent {@code Collector} implementing a cascaded "group by" 765 * operation on input elements of type {@code T}, grouping elements 766 * according to a classification function, and then performing a reduction 767 * operation on the values associated with a given key using the specified 768 * downstream {@code Collector}. The {@code ConcurrentMap} produced by the 769 * Collector is created with the supplied factory function. 770 * 771 * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and 772 * {@link Collector.Characteristics#UNORDERED unordered} Collector. 773 * 774 * <p>The classification function maps elements to some key type {@code K}. 775 * The downstream collector operates on elements of type {@code T} and 776 * produces a result of type {@code D}. The resulting collector produces a 777 * {@code Map<K, D>}. 778 * 779 * <p>For example, to compute the set of last names of people in each city, 780 * where the city names are sorted: 781 * <pre>{@code 782 * ConcurrentMap<City, Set<String>> namesByCity 783 * = people.stream().collect(groupingBy(Person::getCity, ConcurrentSkipListMap::new, 784 * mapping(Person::getLastName, toSet()))); 785 * }</pre> 786 * 787 * 788 * @param <T> the type of the input elements 789 * @param <K> the type of the keys 790 * @param <D> the result type of the downstream reduction 791 * @param <M> the type of the resulting {@code ConcurrentMap} 792 * @param classifier a classifier function mapping input elements to keys 793 * @param downstream a {@code Collector} implementing the downstream reduction 794 * @param mapFactory a function which, when called, produces a new empty 795 * {@code ConcurrentMap} of the desired type 796 * @return a {@code Collector} implementing the cascaded group-by operation 797 * 798 * @see #groupingByConcurrent(Function) 799 * @see #groupingByConcurrent(Function, Collector) 800 * @see #groupingBy(Function, Supplier, Collector) 801 */ 802 public static <T, K, D, M extends ConcurrentMap<K, D>> 803 Collector<T, M> groupingByConcurrent(Function<? super T, ? extends K> classifier, 804 Supplier<M> mapFactory, 805 Collector<? super T, D> downstream) { 806 Supplier<D> downstreamSupplier = downstream.resultSupplier(); 807 BiFunction<D, ? super T, D> downstreamAccumulator = downstream.accumulator(); 808 BinaryOperator<M> combiner = mapMerger(downstream.combiner()); 809 if (downstream.characteristics().contains(Collector.Characteristics.CONCURRENT)) { 810 BiFunction<M, T, M> accumulator = (m, t) -> { 811 K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key"); 812 downstreamAccumulator.apply(m.computeIfAbsent(key, k -> downstreamSupplier.get()), t); 813 return m; 814 }; 815 return new CollectorImpl<>(mapFactory, accumulator, combiner, CH_CONCURRENT); 816 } else if (downstream.characteristics().contains(Collector.Characteristics.STRICTLY_MUTATIVE)) { 817 BiFunction<M, T, M> accumulator = (m, t) -> { 818 K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key"); 819 D resultContainer = m.computeIfAbsent(key, k -> downstreamSupplier.get()); 820 synchronized (resultContainer) { 821 downstreamAccumulator.apply(resultContainer, t); 822 } 823 return m; 824 }; 825 return new CollectorImpl<>(mapFactory, accumulator, combiner, CH_CONCURRENT); 826 } else { 827 BiFunction<M, T, M> accumulator = (m, t) -> { 828 K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key"); 829 do { 830 D oldResult = m.computeIfAbsent(key, k -> downstreamSupplier.get()); 831 if (oldResult == null) { 832 if (m.putIfAbsent(key, downstreamAccumulator.apply(null, t)) == null) 833 return m; 834 } else { 835 synchronized (oldResult) { 836 if (m.get(key) != oldResult) 837 continue; 838 D newResult = downstreamAccumulator.apply(oldResult, t); 839 if (oldResult != newResult) 840 m.put(key, newResult); 841 return m; 842 } 843 } 844 } while (true); 845 }; 846 return new CollectorImpl<>(mapFactory, accumulator, combiner, CH_CONCURRENT); 847 } 848 } 849 850 /** 851 * Returns a {@code Collector} which partitions the input elements according 852 * to a {@code Predicate}, and organizes them into a 853 * {@code Map<Boolean, List<T>>}. 854 * 855 * There are no guarantees on the type, mutability, 856 * serializability, or thread-safety of the {@code Map} returned. 857 * 858 * @param <T> the type of the input elements 859 * @param predicate a predicate used for classifying input elements 860 * @return a {@code Collector} implementing the partitioning operation 861 * 862 * @see #partitioningBy(Predicate, Collector) 863 */ 864 public static <T> 865 Collector<T, Map<Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate) { 866 return partitioningBy(predicate, toList()); 867 } 868 869 /** 870 * Returns a {@code Collector} which partitions the input elements according 871 * to a {@code Predicate}, reduces the values in each partition according to 872 * another {@code Collector}, and organizes them into a 873 * {@code Map<Boolean, D>} whose values are the result of the downstream 874 * reduction. 875 * 876 * <p>There are no guarantees on the type, mutability, 877 * serializability, or thread-safety of the {@code Map} returned. 878 * 879 * @param <T> the type of the input elements 880 * @param <D> the result type of the downstream reduction 881 * @param predicate a predicate used for classifying input elements 882 * @param downstream a {@code Collector} implementing the downstream 883 * reduction 884 * @return a {@code Collector} implementing the cascaded partitioning 885 * operation 886 * 887 * @see #partitioningBy(Predicate) 888 */ 889 public static <T, D> 890 Collector<T, Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate, 891 Collector<? super T, D> downstream) { 892 BiFunction<D, ? super T, D> downstreamAccumulator = downstream.accumulator(); 893 BiFunction<Map<Boolean, D>, T, Map<Boolean, D>> accumulator = (result, t) -> { 894 Partition<D> asPartition = ((Partition<D>) result); 895 if (predicate.test(t)) { 896 D newResult = downstreamAccumulator.apply(asPartition.forTrue, t); 897 if (newResult != asPartition.forTrue) 898 asPartition.forTrue = newResult; 899 } else { 900 D newResult = downstreamAccumulator.apply(asPartition.forFalse, t); 901 if (newResult != asPartition.forFalse) 902 asPartition.forFalse = newResult; 903 } 904 return result; 905 }; 906 return new CollectorImpl<>(() -> new Partition<>(downstream.resultSupplier().get(), 907 downstream.resultSupplier().get()), 908 accumulator, partitionMerger(downstream.combiner()), CH_STRICT); 909 } 910 911 /** 912 * Merge function for two partitions, given a merge function for the 913 * elements. 914 */ 915 private static <D> BinaryOperator<Map<Boolean, D>> partitionMerger(BinaryOperator<D> op) { 916 return (m1, m2) -> { 917 Partition<D> left = (Partition<D>) m1; 918 Partition<D> right = (Partition<D>) m2; 919 if (left.forFalse == null) 920 left.forFalse = right.forFalse; 921 else if (right.forFalse != null) 922 left.forFalse = op.apply(left.forFalse, right.forFalse); 923 if (left.forTrue == null) 924 left.forTrue = right.forTrue; 925 else if (right.forTrue != null) 926 left.forTrue = op.apply(left.forTrue, right.forTrue); 927 return left; 928 }; 929 } 930 931 /** 932 * Accumulate elements into a {@code Map} whose keys and values are the 933 * result of applying mapping functions to the input elements. 934 * If the mapped keys contains duplicates (according to 935 * {@link Object#equals(Object)}), an {@code IllegalStateException} is 936 * thrown when the collection operation is performed. If the mapped keys 937 * may have duplicates, use {@link #toMap(Function, Function, BinaryOperator)} 938 * instead. 939 * 940 * @apiNote 941 * It is common for either the key or the value to be the input elements. 942 * In this case, the utility method 943 * {@link java.util.function.Function#identity()} may be helpful. 944 * For example, the following produces a {@code Map} mapping 945 * students to their grade point average: 946 * <pre>{@code 947 * Map<Student, Double> studentToGPA 948 * students.stream().collect(toMap(Functions.identity(), 949 * student -> computeGPA(student))); 950 * }</pre> 951 * And the following produces a {@code Map} mapping a unique identifier to 952 * students: 953 * <pre>{@code 954 * Map<String, Student> studentIdToStudent 955 * students.stream().collect(toMap(Student::getId, 956 * Functions.identity()); 957 * }</pre> 958 * 959 * @param <T> the type of the input elements 960 * @param <K> the output type of the key mapping function 961 * @param <U> the output type of the value mapping function 962 * @param keyMapper a mapping function to produce keys 963 * @param valueMapper a mapping function to produce values 964 * @return a {@code Collector} which collects elements into a {@code Map} 965 * whose keys and values are the result of applying mapping functions to 966 * the input elements 967 * 968 * @see #toMap(Function, Function, BinaryOperator) 969 * @see #toMap(Function, Function, BinaryOperator, Supplier) 970 * @see #toConcurrentMap(Function, Function) 971 */ 972 public static <T, K, U> 973 Collector<T, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper, 974 Function<? super T, ? extends U> valueMapper) { 975 return toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new); 976 } 977 978 /** 979 * Accumulate elements into a {@code Map} whose keys and values are the 980 * result of applying mapping functions to the input elements. If the mapped 981 * keys contains duplicates (according to {@link Object#equals(Object)}), 982 * the value mapping function is applied to each equal element, and the 983 * results are merged using the provided merging function. 984 * 985 * @apiNote 986 * There are multiple ways to deal with collisions between multiple elements 987 * mapping to the same key. There are some predefined merging functions, 988 * such as {@link #throwingMerger()}, {@link #firstWinsMerger()}, and 989 * {@link #lastWinsMerger()}, that implement common policies, or you can 990 * implement custom policies easily. For example, if you have a stream 991 * of {@code Person}, and you want to produce a "phone book" mapping name to 992 * address, but it is possible that two persons have the same name, you can 993 * do as follows to gracefully deals with these collisions, and produce a 994 * {@code Map} mapping names to a concatenated list of addresses: 995 * <pre>{@code 996 * Map<String, String> phoneBook 997 * people.stream().collect(toMap(Person::getName, 998 * Person::getAddress, 999 * (s, a) -> s + ", " + a)); 1000 * }</pre> 1001 * 1002 * @param <T> the type of the input elements 1003 * @param <K> the output type of the key mapping function 1004 * @param <U> the output type of the value mapping function 1005 * @param keyMapper a mapping function to produce keys 1006 * @param valueMapper a mapping function to produce values 1007 * @param mergeFunction a merge function, used to resolve collisions between 1008 * values associated with the same key, as supplied 1009 * to {@link Map#merge(Object, Object, BiFunction)} 1010 * @return a {@code Collector} which collects elements into a {@code Map} 1011 * whose keys are the result of applying a key mapping function to the input 1012 * elements, and whose values are the result of applying a value mapping 1013 * function to all input elements equal to the key and combining them 1014 * using the merge function 1015 * 1016 * @see #toMap(Function, Function) 1017 * @see #toMap(Function, Function, BinaryOperator, Supplier) 1018 * @see #toConcurrentMap(Function, Function, BinaryOperator) 1019 */ 1020 public static <T, K, U> 1021 Collector<T, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper, 1022 Function<? super T, ? extends U> valueMapper, 1023 BinaryOperator<U> mergeFunction) { 1024 return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new); 1025 } 1026 1027 /** 1028 * Accumulate elements into a {@code Map} whose keys and values are the 1029 * result of applying mapping functions to the input elements. If the mapped 1030 * keys contains duplicates (according to {@link Object#equals(Object)}), 1031 * the value mapping function is applied to each equal element, and the 1032 * results are merged using the provided merging function. The {@code Map} 1033 * is created by a provided supplier function. 1034 * 1035 * @param <T> the type of the input elements 1036 * @param <K> the output type of the key mapping function 1037 * @param <U> the output type of the value mapping function 1038 * @param <M> the type of the resulting {@code Map} 1039 * @param keyMapper a mapping function to produce keys 1040 * @param valueMapper a mapping function to produce values 1041 * @param mergeFunction a merge function, used to resolve collisions between 1042 * values associated with the same key, as supplied 1043 * to {@link Map#merge(Object, Object, BiFunction)} 1044 * @param mapSupplier a function which returns a new, empty {@code Map} into 1045 * which the results will be inserted 1046 * @return a {@code Collector} which collects elements into a {@code Map} 1047 * whose keys are the result of applying a key mapping function to the input 1048 * elements, and whose values are the result of applying a value mapping 1049 * function to all input elements equal to the key and combining them 1050 * using the merge function 1051 * 1052 * @see #toMap(Function, Function) 1053 * @see #toMap(Function, Function, BinaryOperator) 1054 * @see #toConcurrentMap(Function, Function, BinaryOperator, Supplier) 1055 */ 1056 public static <T, K, U, M extends Map<K, U>> 1057 Collector<T, M> toMap(Function<? super T, ? extends K> keyMapper, 1058 Function<? super T, ? extends U> valueMapper, 1059 BinaryOperator<U> mergeFunction, 1060 Supplier<M> mapSupplier) { 1061 BiFunction<M, T, M> accumulator 1062 = (map, element) -> { 1063 map.merge(keyMapper.apply(element), valueMapper.apply(element), mergeFunction); 1064 return map; 1065 }; 1066 return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_STRICT); 1067 } 1068 1069 /** 1070 * Accumulate elements into a {@code ConcurrentMap} whose keys and values 1071 * are the result of applying mapping functions to the input elements. 1072 * If the mapped keys contains duplicates (according to 1073 * {@link Object#equals(Object)}), an {@code IllegalStateException} is 1074 * thrown when the collection operation is performed. If the mapped keys 1075 * may have duplicates, use 1076 * {@link #toConcurrentMap(Function, Function, BinaryOperator)} instead. 1077 * 1078 * @apiNote 1079 * It is common for either the key or the value to be the input elements. 1080 * In this case, the utility method 1081 * {@link java.util.function.Function#identity()} may be helpful. 1082 * For example, the following produces a {@code Map} mapping 1083 * students to their grade point average: 1084 * <pre>{@code 1085 * Map<Student, Double> studentToGPA 1086 * students.stream().collect(toMap(Functions.identity(), 1087 * student -> computeGPA(student))); 1088 * }</pre> 1089 * And the following produces a {@code Map} mapping a unique identifier to 1090 * students: 1091 * <pre>{@code 1092 * Map<String, Student> studentIdToStudent 1093 * students.stream().collect(toConcurrentMap(Student::getId, 1094 * Functions.identity()); 1095 * }</pre> 1096 * 1097 * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and 1098 * {@link Collector.Characteristics#UNORDERED unordered} Collector. 1099 * 1100 * @param <T> the type of the input elements 1101 * @param <K> the output type of the key mapping function 1102 * @param <U> the output type of the value mapping function 1103 * @param keyMapper the mapping function to produce keys 1104 * @param valueMapper the mapping function to produce values 1105 * @return a concurrent {@code Collector} which collects elements into a 1106 * {@code ConcurrentMap} whose keys are the result of applying a key mapping 1107 * function to the input elements, and whose values are the result of 1108 * applying a value mapping function to the input elements 1109 * 1110 * @see #toMap(Function, Function) 1111 * @see #toConcurrentMap(Function, Function, BinaryOperator) 1112 * @see #toConcurrentMap(Function, Function, BinaryOperator, Supplier) 1113 */ 1114 public static <T, K, U> 1115 Collector<T, ConcurrentMap<K,U>> toConcurrentMap(Function<? super T, ? extends K> keyMapper, 1116 Function<? super T, ? extends U> valueMapper) { 1117 return toConcurrentMap(keyMapper, valueMapper, throwingMerger(), ConcurrentHashMap::new); 1118 } 1119 1120 /** 1121 * Accumulate elements into a {@code ConcurrentMap} whose keys and values 1122 * are the result of applying mapping functions to the input elements. If 1123 * the mapped keys contains duplicates (according to {@link Object#equals(Object)}), 1124 * the value mapping function is applied to each equal element, and the 1125 * results are merged using the provided merging function. 1126 * 1127 * @apiNote 1128 * There are multiple ways to deal with collisions between multiple elements 1129 * mapping to the same key. There are some predefined merging functions, 1130 * such as {@link #throwingMerger()}, {@link #firstWinsMerger()}, and 1131 * {@link #lastWinsMerger()}, that implement common policies, or you can 1132 * implement custom policies easily. For example, if you have a stream 1133 * of {@code Person}, and you want to produce a "phone book" mapping name to 1134 * address, but it is possible that two persons have the same name, you can 1135 * do as follows to gracefully deals with these collisions, and produce a 1136 * {@code Map} mapping names to a concatenated list of addresses: 1137 * <pre>{@code 1138 * Map<String, String> phoneBook 1139 * people.stream().collect(toConcurrentMap(Person::getName, 1140 * Person::getAddress, 1141 * (s, a) -> s + ", " + a)); 1142 * }</pre> 1143 * 1144 * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and 1145 * {@link Collector.Characteristics#UNORDERED unordered} Collector. 1146 * 1147 * @param <T> the type of the input elements 1148 * @param <K> the output type of the key mapping function 1149 * @param <U> the output type of the value mapping function 1150 * @param keyMapper a mapping function to produce keys 1151 * @param valueMapper a mapping function to produce values 1152 * @param mergeFunction a merge function, used to resolve collisions between 1153 * values associated with the same key, as supplied 1154 * to {@link Map#merge(Object, Object, BiFunction)} 1155 * @return a concurrent {@code Collector} which collects elements into a 1156 * {@code ConcurrentMap} whose keys are the result of applying a key mapping 1157 * function to the input elements, and whose values are the result of 1158 * applying a value mapping function to all input elements equal to the key 1159 * and combining them using the merge function 1160 * 1161 * @see #toConcurrentMap(Function, Function) 1162 * @see #toConcurrentMap(Function, Function, BinaryOperator, Supplier) 1163 * @see #toMap(Function, Function, BinaryOperator) 1164 */ 1165 public static <T, K, U> 1166 Collector<T, ConcurrentMap<K,U>> toConcurrentMap(Function<? super T, ? extends K> keyMapper, 1167 Function<? super T, ? extends U> valueMapper, 1168 BinaryOperator<U> mergeFunction) { 1169 return toConcurrentMap(keyMapper, valueMapper, mergeFunction, ConcurrentHashMap::new); 1170 } 1171 1172 /** 1173 * Accumulate elements into a {@code ConcurrentMap} whose keys and values 1174 * are the result of applying mapping functions to the input elements. If 1175 * the mapped keys contains duplicates (according to {@link Object#equals(Object)}), 1176 * the value mapping function is applied to each equal element, and the 1177 * results are merged using the provided merging function. The 1178 * {@code ConcurrentMap} is created by a provided supplier function. 1179 * 1180 * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and 1181 * {@link Collector.Characteristics#UNORDERED unordered} Collector. 1182 * 1183 * @param <T> the type of the input elements 1184 * @param <K> the output type of the key mapping function 1185 * @param <U> the output type of the value mapping function 1186 * @param <M> the type of the resulting {@code ConcurrentMap} 1187 * @param keyMapper a mapping function to produce keys 1188 * @param valueMapper a mapping function to produce values 1189 * @param mergeFunction a merge function, used to resolve collisions between 1190 * values associated with the same key, as supplied 1191 * to {@link Map#merge(Object, Object, BiFunction)} 1192 * @param mapSupplier a function which returns a new, empty {@code Map} into 1193 * which the results will be inserted 1194 * @return a concurrent {@code Collector} which collects elements into a 1195 * {@code ConcurrentMap} whose keys are the result of applying a key mapping 1196 * function to the input elements, and whose values are the result of 1197 * applying a value mapping function to all input elements equal to the key 1198 * and combining them using the merge function 1199 * 1200 * @see #toConcurrentMap(Function, Function) 1201 * @see #toConcurrentMap(Function, Function, BinaryOperator) 1202 * @see #toMap(Function, Function, BinaryOperator, Supplier) 1203 */ 1204 public static <T, K, U, M extends ConcurrentMap<K, U>> 1205 Collector<T, M> toConcurrentMap(Function<? super T, ? extends K> keyMapper, 1206 Function<? super T, ? extends U> valueMapper, 1207 BinaryOperator<U> mergeFunction, 1208 Supplier<M> mapSupplier) { 1209 BiFunction<M, T, M> accumulator = (map, element) -> { 1210 map.merge(keyMapper.apply(element), valueMapper.apply(element), mergeFunction); 1211 return map; 1212 }; 1213 return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_CONCURRENT); 1214 } 1215 1216 /** 1217 * Returns a {@code Collector} which applies an {@code int}-producing 1218 * mapping function to each input element, and returns summary statistics 1219 * for the resulting values. 1220 * 1221 * @param <T> the type of the input elements 1222 * @param mapper a mapping function to apply to each element 1223 * @return a {@code Collector} implementing the summary-statistics reduction 1224 * 1225 * @see #toDoubleSummaryStatistics(ToDoubleFunction) 1226 * @see #toLongSummaryStatistics(ToLongFunction) 1227 */ 1228 public static <T> 1229 Collector<T, IntSummaryStatistics> toIntSummaryStatistics(ToIntFunction<? super T> mapper) { 1230 return new CollectorImpl<>(IntSummaryStatistics::new, 1231 (r, t) -> { r.accept(mapper.applyAsInt(t)); return r; }, 1232 (l, r) -> { l.combine(r); return l; }, CH_STRICT); 1233 } 1234 1235 /** 1236 * Returns a {@code Collector} which applies an {@code long}-producing 1237 * mapping function to each input element, and returns summary statistics 1238 * for the resulting values. 1239 * 1240 * @param <T> the type of the input elements 1241 * @param mapper the mapping function to apply to each element 1242 * @return a {@code Collector} implementing the summary-statistics reduction 1243 * 1244 * @see #toDoubleSummaryStatistics(ToDoubleFunction) 1245 * @see #toIntSummaryStatistics(ToIntFunction) 1246 */ 1247 public static <T> 1248 Collector<T, LongSummaryStatistics> toLongSummaryStatistics(ToLongFunction<? super T> mapper) { 1249 return new CollectorImpl<>(LongSummaryStatistics::new, 1250 (r, t) -> { r.accept(mapper.applyAsLong(t)); return r; }, 1251 (l, r) -> { l.combine(r); return l; }, CH_STRICT); 1252 } 1253 1254 /** 1255 * Returns a {@code Collector} which applies an {@code double}-producing 1256 * mapping function to each input element, and returns summary statistics 1257 * for the resulting values. 1258 * 1259 * @param <T> the type of the input elements 1260 * @param mapper a mapping function to apply to each element 1261 * @return a {@code Collector} implementing the summary-statistics reduction 1262 * 1263 * @see #toLongSummaryStatistics(ToLongFunction) 1264 * @see #toIntSummaryStatistics(ToIntFunction) 1265 */ 1266 public static <T> 1267 Collector<T, DoubleSummaryStatistics> toDoubleSummaryStatistics(ToDoubleFunction<? super T> mapper) { 1268 return new CollectorImpl<>(DoubleSummaryStatistics::new, 1269 (r, t) -> { r.accept(mapper.applyAsDouble(t)); return r; }, 1270 (l, r) -> { l.combine(r); return l; }, CH_STRICT); 1271 } 1272 1273 /** 1274 * Implementation class used by partitioningBy. 1275 */ 1276 private static final class Partition<T> 1277 extends AbstractMap<Boolean, T> 1278 implements Map<Boolean, T> { 1279 T forTrue; 1280 T forFalse; 1281 1282 Partition(T forTrue, T forFalse) { 1283 this.forTrue = forTrue; 1284 this.forFalse = forFalse; 1285 } 1286 1287 @Override 1288 public Set<Map.Entry<Boolean, T>> entrySet() { 1289 return new AbstractSet<Map.Entry<Boolean, T>>() { 1290 @Override 1291 public Iterator<Map.Entry<Boolean, T>> iterator() { 1292 1293 return new Iterator<Map.Entry<Boolean, T>>() { 1294 int state = 0; 1295 1296 @Override 1297 public boolean hasNext() { 1298 return state < 2; 1299 } 1300 1301 @Override 1302 public Map.Entry<Boolean, T> next() { 1303 if (state >= 2) 1304 throw new NoSuchElementException(); 1305 return (state++ == 0) 1306 ? new SimpleImmutableEntry<>(false, forFalse) 1307 : new SimpleImmutableEntry<>(true, forTrue); 1308 } 1309 }; 1310 } 1311 1312 @Override 1313 public int size() { 1314 return 2; 1315 } 1316 }; 1317 } 1318 } 1319 }