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 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.Objects; 43 import java.util.Optional; 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.BiConsumer; 49 import java.util.function.BiFunction; 50 import java.util.function.BinaryOperator; 51 import java.util.function.Consumer; 52 import java.util.function.Function; 53 import java.util.function.Predicate; 54 import java.util.function.Supplier; 55 import java.util.function.ToDoubleFunction; 56 import java.util.function.ToIntFunction; 57 import java.util.function.ToLongFunction; 58 59 /** 60 * Implementations of {@link Collector} that implement various useful reduction 61 * operations, such as accumulating elements into collections, summarizing 62 * elements according to various criteria, etc. 63 * 64 * <p>The following are examples of using the predefined collectors to perform 65 * common mutable reduction tasks: 66 * 67 * <pre>{@code 68 * // Accumulate names into a List 69 * List<String> list = people.stream().map(Person::getName).collect(Collectors.toList()); 70 * 71 * // Accumulate names into a TreeSet 72 * Set<String> set = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new)); 73 * 74 * // Convert elements to strings and concatenate them, separated by commas 75 * String joined = things.stream() 76 * .map(Object::toString) 77 * .collect(Collectors.joining(", ")); 78 * 79 * // Compute sum of salaries of employee 80 * int total = employees.stream() 81 * .collect(Collectors.summingInt(Employee::getSalary))); 82 * 83 * // Group employees by department 84 * Map<Department, List<Employee>> byDept 85 * = employees.stream() 86 * .collect(Collectors.groupingBy(Employee::getDepartment)); 87 * 88 * // Compute sum of salaries by department 89 * Map<Department, Integer> totalByDept 90 * = employees.stream() 91 * .collect(Collectors.groupingBy(Employee::getDepartment, 92 * Collectors.summingInt(Employee::getSalary))); 93 * 94 * // Partition students into passing and failing 95 * Map<Boolean, List<Student>> passingFailing = 96 * students.stream() 97 * .collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD)); 98 * 99 * }</pre> 100 * 101 * @since 1.8 102 */ 103 public final class Collectors { 104 105 static final Set<Collector.Characteristics> CH_CONCURRENT_ID 106 = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.CONCURRENT, 107 Collector.Characteristics.UNORDERED, 108 Collector.Characteristics.IDENTITY_FINISH)); 109 static final Set<Collector.Characteristics> CH_CONCURRENT_NOID 110 = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.CONCURRENT, 111 Collector.Characteristics.UNORDERED)); 112 static final Set<Collector.Characteristics> CH_ID 113 = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH)); 114 static final Set<Collector.Characteristics> CH_UNORDERED_ID 115 = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.UNORDERED, 116 Collector.Characteristics.IDENTITY_FINISH)); 117 static final Set<Collector.Characteristics> CH_NOID = Collections.emptySet(); 118 119 private Collectors() { } 120 121 /** 122 * Construct an {@code IllegalStateException} with appropriate message. 123 * 124 * @param k the duplicate key 125 * @param u 1st value to be accumulated/merged 126 * @param v 2nd value to be accumulated/merged 127 */ 128 private static IllegalStateException duplicateKeyException( 129 Object k, Object u, Object v) { 130 return new IllegalStateException(String.format( 131 "Duplicate key %s (attempted merging values %s and %s)", 132 k, u, v)); 133 } 134 135 /** 136 * {@code BinaryOperator<Map>} that merges the contents of its right 137 * argument into its left argument, throwing {@code IllegalStateException} 138 * if duplicate keys are encountered. 139 * 140 * @param <K> type of the map keys 141 * @param <V> type of the map values 142 * @param <M> type of the map 143 * @return a merge function for two maps 144 */ 145 private static <K, V, M extends Map<K,V>> 146 BinaryOperator<M> uniqKeysMapMerger() { 147 return (m1, m2) -> { 148 for (Map.Entry<K,V> e : m2.entrySet()) { 149 K k = e.getKey(); 150 V v = Objects.requireNonNull(e.getValue()); 151 V u = m1.putIfAbsent(k, v); 152 if (u != null) throw duplicateKeyException(k, u, v); 153 } 154 return m1; 155 }; 156 } 157 158 /** 159 * {@code BiConsumer<Map, T>} that accumulates (key, value) pairs 160 * extracted from elements into the map, throwing {@code IllegalStateException} 161 * if duplicate keys are encountered. 162 * 163 * @param keyMapper a function that maps an element into a key 164 * @param valueMapper a function that maps an element into a value 165 * @param <T> type of elements 166 * @param <K> type of map keys 167 * @param <V> type of map values 168 * @return an accumulating consumer 169 */ 170 private static <T, K, V> 171 BiConsumer<Map<K, V>, T> uniqKeysMapAccumulator(Function<? super T, ? extends K> keyMapper, 172 Function<? super T, ? extends V> valueMapper) { 173 return (map, element) -> { 174 K k = keyMapper.apply(element); 175 V v = Objects.requireNonNull(valueMapper.apply(element)); 176 V u = map.putIfAbsent(k, v); 177 if (u != null) throw duplicateKeyException(k, u, v); 178 }; 179 } 180 181 @SuppressWarnings("unchecked") 182 private static <I, R> Function<I, R> castingIdentity() { 183 return i -> (R) i; 184 } 185 186 /** 187 * Simple implementation class for {@code Collector}. 188 * 189 * @param <T> the type of elements to be collected 190 * @param <R> the type of the result 191 */ 192 static class CollectorImpl<T, A, R> implements Collector<T, A, R> { 193 private final Supplier<A> supplier; 194 private final BiConsumer<A, T> accumulator; 195 private final BinaryOperator<A> combiner; 196 private final Function<A, R> finisher; 197 private final Set<Characteristics> characteristics; 198 199 CollectorImpl(Supplier<A> supplier, 200 BiConsumer<A, T> accumulator, 201 BinaryOperator<A> combiner, 202 Function<A,R> finisher, 203 Set<Characteristics> characteristics) { 204 this.supplier = supplier; 205 this.accumulator = accumulator; 206 this.combiner = combiner; 207 this.finisher = finisher; 208 this.characteristics = characteristics; 209 } 210 211 CollectorImpl(Supplier<A> supplier, 212 BiConsumer<A, T> accumulator, 213 BinaryOperator<A> combiner, 214 Set<Characteristics> characteristics) { 215 this(supplier, accumulator, combiner, castingIdentity(), characteristics); 216 } 217 218 @Override 219 public BiConsumer<A, T> accumulator() { 220 return accumulator; 221 } 222 223 @Override 224 public Supplier<A> supplier() { 225 return supplier; 226 } 227 228 @Override 229 public BinaryOperator<A> combiner() { 230 return combiner; 231 } 232 233 @Override 234 public Function<A, R> finisher() { 235 return finisher; 236 } 237 238 @Override 239 public Set<Characteristics> characteristics() { 240 return characteristics; 241 } 242 } 243 244 /** 245 * Returns a {@code Collector} that accumulates the input elements into a 246 * new {@code Collection}, in encounter order. The {@code Collection} is 247 * created by the provided factory. 248 * 249 * @param <T> the type of the input elements 250 * @param <C> the type of the resulting {@code Collection} 251 * @param collectionFactory a {@code Supplier} which returns a new, empty 252 * {@code Collection} of the appropriate type 253 * @return a {@code Collector} which collects all the input elements into a 254 * {@code Collection}, in encounter order 255 */ 256 public static <T, C extends Collection<T>> 257 Collector<T, ?, C> toCollection(Supplier<C> collectionFactory) { 258 return new CollectorImpl<>(collectionFactory, Collection<T>::add, 259 (r1, r2) -> { r1.addAll(r2); return r1; }, 260 CH_ID); 261 } 262 263 /** 264 * Returns a {@code Collector} that accumulates the input elements into a 265 * new {@code List}. There are no guarantees on the type, mutability, 266 * serializability, or thread-safety of the {@code List} returned; if more 267 * control over the returned {@code List} is required, use {@link #toCollection(Supplier)}. 268 * 269 * @param <T> the type of the input elements 270 * @return a {@code Collector} which collects all the input elements into a 271 * {@code List}, in encounter order 272 */ 273 public static <T> 274 Collector<T, ?, List<T>> toList() { 275 return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add, 276 (left, right) -> { left.addAll(right); return left; }, 277 CH_ID); 278 } 279 280 /** 281 * Returns a {@code Collector} that accumulates the input elements into a 282 * new {@code Set}. There are no guarantees on the type, mutability, 283 * serializability, or thread-safety of the {@code Set} returned; if more 284 * control over the returned {@code Set} is required, use 285 * {@link #toCollection(Supplier)}. 286 * 287 * <p>This is an {@link Collector.Characteristics#UNORDERED unordered} 288 * Collector. 289 * 290 * @param <T> the type of the input elements 291 * @return a {@code Collector} which collects all the input elements into a 292 * {@code Set} 293 */ 294 public static <T> 295 Collector<T, ?, Set<T>> toSet() { 296 return new CollectorImpl<>((Supplier<Set<T>>) HashSet::new, Set::add, 297 (left, right) -> { 298 if (left.size() < right.size()) { 299 right.addAll(left); return right; 300 } else { 301 left.addAll(right); return left; 302 } 303 }, 304 CH_UNORDERED_ID); 305 } 306 307 /** 308 * Returns a {@code Collector} that concatenates the input elements into a 309 * {@code String}, in encounter order. 310 * 311 * @return a {@code Collector} that concatenates the input elements into a 312 * {@code String}, in encounter order 313 */ 314 public static Collector<CharSequence, ?, String> joining() { 315 return new CollectorImpl<CharSequence, StringBuilder, String>( 316 StringBuilder::new, StringBuilder::append, 317 (r1, r2) -> { r1.append(r2); return r1; }, 318 StringBuilder::toString, CH_NOID); 319 } 320 321 /** 322 * Returns a {@code Collector} that concatenates the input elements, 323 * separated by the specified delimiter, in encounter order. 324 * 325 * @param delimiter the delimiter to be used between each element 326 * @return A {@code Collector} which concatenates CharSequence elements, 327 * separated by the specified delimiter, in encounter order 328 */ 329 public static Collector<CharSequence, ?, String> joining(CharSequence delimiter) { 330 return joining(delimiter, "", ""); 331 } 332 333 /** 334 * Returns a {@code Collector} that concatenates the input elements, 335 * separated by the specified delimiter, with the specified prefix and 336 * suffix, in encounter order. 337 * 338 * @param delimiter the delimiter to be used between each element 339 * @param prefix the sequence of characters to be used at the beginning 340 * of the joined result 341 * @param suffix the sequence of characters to be used at the end 342 * of the joined result 343 * @return A {@code Collector} which concatenates CharSequence elements, 344 * separated by the specified delimiter, in encounter order 345 */ 346 public static Collector<CharSequence, ?, String> joining(CharSequence delimiter, 347 CharSequence prefix, 348 CharSequence suffix) { 349 return new CollectorImpl<>( 350 () -> new StringJoiner(delimiter, prefix, suffix), 351 StringJoiner::add, StringJoiner::merge, 352 StringJoiner::toString, CH_NOID); 353 } 354 355 /** 356 * {@code BinaryOperator<Map>} that merges the contents of its right 357 * argument into its left argument, using the provided merge function to 358 * handle duplicate keys. 359 * 360 * @param <K> type of the map keys 361 * @param <V> type of the map values 362 * @param <M> type of the map 363 * @param mergeFunction A merge function suitable for 364 * {@link Map#merge(Object, Object, BiFunction) Map.merge()} 365 * @return a merge function for two maps 366 */ 367 private static <K, V, M extends Map<K,V>> 368 BinaryOperator<M> mapMerger(BinaryOperator<V> mergeFunction) { 369 return (m1, m2) -> { 370 for (Map.Entry<K,V> e : m2.entrySet()) 371 m1.merge(e.getKey(), e.getValue(), mergeFunction); 372 return m1; 373 }; 374 } 375 376 /** 377 * Adapts a {@code Collector} accepting elements of type {@code U} to one 378 * accepting elements of type {@code T} by applying a mapping function to 379 * each input element before accumulation. 380 * 381 * @apiNote 382 * The {@code mapping()} collectors are most useful when used in a 383 * multi-level reduction, such as downstream of a {@code groupingBy} or 384 * {@code partitioningBy}. For example, given a stream of 385 * {@code Person}, to accumulate the set of last names in each city: 386 * <pre>{@code 387 * Map<City, Set<String>> lastNamesByCity 388 * = people.stream().collect(groupingBy(Person::getCity, 389 * mapping(Person::getLastName, toSet()))); 390 * }</pre> 391 * 392 * @param <T> the type of the input elements 393 * @param <U> type of elements accepted by downstream collector 394 * @param <A> intermediate accumulation type of the downstream collector 395 * @param <R> result type of collector 396 * @param mapper a function to be applied to the input elements 397 * @param downstream a collector which will accept mapped values 398 * @return a collector which applies the mapping function to the input 399 * elements and provides the mapped results to the downstream collector 400 */ 401 public static <T, U, A, R> 402 Collector<T, ?, R> mapping(Function<? super T, ? extends U> mapper, 403 Collector<? super U, A, R> downstream) { 404 BiConsumer<A, ? super U> downstreamAccumulator = downstream.accumulator(); 405 return new CollectorImpl<>(downstream.supplier(), 406 (r, t) -> downstreamAccumulator.accept(r, mapper.apply(t)), 407 downstream.combiner(), downstream.finisher(), 408 downstream.characteristics()); 409 } 410 411 /** 412 * Adapts a {@code Collector} accepting elements of type {@code U} to one 413 * accepting elements of type {@code T} by applying a flat mapping function 414 * to each input element before accumulation. The flat mapping function 415 * maps an input element to a {@link Stream stream} covering zero or more 416 * output elements that are then accumulated downstream. Each mapped stream 417 * is {@link java.util.stream.BaseStream#close() closed} after its contents 418 * have been placed downstream. (If a mapped stream is {@code null} 419 * an empty stream is used, instead.) 420 * 421 * @apiNote 422 * The {@code flatMapping()} collectors are most useful when used in a 423 * multi-level reduction, such as downstream of a {@code groupingBy} or 424 * {@code partitioningBy}. For example, given a stream of 425 * {@code Order}, to accumulate the set of line items for each customer: 426 * <pre>{@code 427 * Map<String, Set<LineItem>> itemsByCustomerName 428 * = orders.stream().collect(groupingBy(Order::getCustomerName, 429 * flatMapping(order -> order.getLineItems().stream(), toSet()))); 430 * }</pre> 431 * 432 * @param <T> the type of the input elements 433 * @param <U> type of elements accepted by downstream collector 434 * @param <A> intermediate accumulation type of the downstream collector 435 * @param <R> result type of collector 436 * @param mapper a function to be applied to the input elements, which 437 * returns a stream of results 438 * @param downstream a collector which will receive the elements of the 439 * stream returned by mapper 440 * @return a collector which applies the mapping function to the input 441 * elements and provides the flat mapped results to the downstream collector 442 * @since 9 443 */ 444 public static <T, U, A, R> 445 Collector<T, ?, R> flatMapping(Function<? super T, ? extends Stream<? extends U>> mapper, 446 Collector<? super U, A, R> downstream) { 447 BiConsumer<A, ? super U> downstreamAccumulator = downstream.accumulator(); 448 return new CollectorImpl<>(downstream.supplier(), 449 (r, t) -> { 450 try (Stream<? extends U> result = mapper.apply(t)) { 451 if (result != null) 452 result.sequential().forEach(u -> downstreamAccumulator.accept(r, u)); 453 } 454 }, 455 downstream.combiner(), downstream.finisher(), 456 downstream.characteristics()); 457 } 458 459 /** 460 * Adapts a {@code Collector} to one accepting elements of the same type 461 * {@code T} by applying the predicate to each input element and only 462 * accumulating if the predicate returns {@code true}. 463 * 464 * @apiNote 465 * The {@code filtering()} collectors are most useful when used in a 466 * multi-level reduction, such as downstream of a {@code groupingBy} or 467 * {@code partitioningBy}. For example, given a stream of 468 * {@code Employee}, to accumulate the employees in each department that have a 469 * salary above a certain threshold: 470 * <pre>{@code 471 * Map<Department, Set<Employee>> wellPaidEmployeesByDepartment 472 * = employees.stream().collect(groupingBy(Employee::getDepartment, 473 * filtering(e -> e.getSalary() > 2000, toSet()))); 474 * }</pre> 475 * A filtering collector differs from a stream's {@code filter()} operation. 476 * In this example, suppose there are no employees whose salary is above the 477 * threshold in some department. Using a filtering collector as shown above 478 * would result in a mapping from that department to an empty {@code Set}. 479 * If a stream {@code filter()} operation were done instead, there would be 480 * no mapping for that department at all. 481 * 482 * @param <T> the type of the input elements 483 * @param <A> intermediate accumulation type of the downstream collector 484 * @param <R> result type of collector 485 * @param predicate a predicate to be applied to the input elements 486 * @param downstream a collector which will accept values that match the 487 * predicate 488 * @return a collector which applies the predicate to the input elements 489 * and provides matching elements to the downstream collector 490 * @since 9 491 */ 492 public static <T, A, R> 493 Collector<T, ?, R> filtering(Predicate<? super T> predicate, 494 Collector<? super T, A, R> downstream) { 495 BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator(); 496 return new CollectorImpl<>(downstream.supplier(), 497 (r, t) -> { 498 if (predicate.test(t)) { 499 downstreamAccumulator.accept(r, t); 500 } 501 }, 502 downstream.combiner(), downstream.finisher(), 503 downstream.characteristics()); 504 } 505 506 /** 507 * Adapts a {@code Collector} to perform an additional finishing 508 * transformation. For example, one could adapt the {@link #toList()} 509 * collector to always produce an immutable list with: 510 * <pre>{@code 511 * List<String> people 512 * = people.stream().collect(collectingAndThen(toList(), Collections::unmodifiableList)); 513 * }</pre> 514 * 515 * @param <T> the type of the input elements 516 * @param <A> intermediate accumulation type of the downstream collector 517 * @param <R> result type of the downstream collector 518 * @param <RR> result type of the resulting collector 519 * @param downstream a collector 520 * @param finisher a function to be applied to the final result of the downstream collector 521 * @return a collector which performs the action of the downstream collector, 522 * followed by an additional finishing step 523 */ 524 public static<T,A,R,RR> Collector<T,A,RR> collectingAndThen(Collector<T,A,R> downstream, 525 Function<R,RR> finisher) { 526 Set<Collector.Characteristics> characteristics = downstream.characteristics(); 527 if (characteristics.contains(Collector.Characteristics.IDENTITY_FINISH)) { 528 if (characteristics.size() == 1) 529 characteristics = Collectors.CH_NOID; 530 else { 531 characteristics = EnumSet.copyOf(characteristics); 532 characteristics.remove(Collector.Characteristics.IDENTITY_FINISH); 533 characteristics = Collections.unmodifiableSet(characteristics); 534 } 535 } 536 return new CollectorImpl<>(downstream.supplier(), 537 downstream.accumulator(), 538 downstream.combiner(), 539 downstream.finisher().andThen(finisher), 540 characteristics); 541 } 542 543 /** 544 * Returns a {@code Collector} accepting elements of type {@code T} that 545 * counts the number of input elements. If no elements are present, the 546 * result is 0. 547 * 548 * @implSpec 549 * This produces a result equivalent to: 550 * <pre>{@code 551 * reducing(0L, e -> 1L, Long::sum) 552 * }</pre> 553 * 554 * @param <T> the type of the input elements 555 * @return a {@code Collector} that counts the input elements 556 */ 557 public static <T> Collector<T, ?, Long> 558 counting() { 559 return summingLong(e -> 1L); 560 } 561 562 /** 563 * Returns a {@code Collector} that produces the minimal element according 564 * to a given {@code Comparator}, described as an {@code Optional<T>}. 565 * 566 * @implSpec 567 * This produces a result equivalent to: 568 * <pre>{@code 569 * reducing(BinaryOperator.minBy(comparator)) 570 * }</pre> 571 * 572 * @param <T> the type of the input elements 573 * @param comparator a {@code Comparator} for comparing elements 574 * @return a {@code Collector} that produces the minimal value 575 */ 576 public static <T> Collector<T, ?, Optional<T>> 577 minBy(Comparator<? super T> comparator) { 578 return reducing(BinaryOperator.minBy(comparator)); 579 } 580 581 /** 582 * Returns a {@code Collector} that produces the maximal element according 583 * to a given {@code Comparator}, described as an {@code Optional<T>}. 584 * 585 * @implSpec 586 * This produces a result equivalent to: 587 * <pre>{@code 588 * reducing(BinaryOperator.maxBy(comparator)) 589 * }</pre> 590 * 591 * @param <T> the type of the input elements 592 * @param comparator a {@code Comparator} for comparing elements 593 * @return a {@code Collector} that produces the maximal value 594 */ 595 public static <T> Collector<T, ?, Optional<T>> 596 maxBy(Comparator<? super T> comparator) { 597 return reducing(BinaryOperator.maxBy(comparator)); 598 } 599 600 /** 601 * Returns a {@code Collector} that produces the sum of a integer-valued 602 * function applied to the input elements. If no elements are present, 603 * the result is 0. 604 * 605 * @param <T> the type of the input elements 606 * @param mapper a function extracting the property to be summed 607 * @return a {@code Collector} that produces the sum of a derived property 608 */ 609 public static <T> Collector<T, ?, Integer> 610 summingInt(ToIntFunction<? super T> mapper) { 611 return new CollectorImpl<>( 612 () -> new int[1], 613 (a, t) -> { a[0] += mapper.applyAsInt(t); }, 614 (a, b) -> { a[0] += b[0]; return a; }, 615 a -> a[0], CH_NOID); 616 } 617 618 /** 619 * Returns a {@code Collector} that produces the sum of a long-valued 620 * function applied to the input elements. If no elements are present, 621 * the result is 0. 622 * 623 * @param <T> the type of the input elements 624 * @param mapper a function extracting the property to be summed 625 * @return a {@code Collector} that produces the sum of a derived property 626 */ 627 public static <T> Collector<T, ?, Long> 628 summingLong(ToLongFunction<? super T> mapper) { 629 return new CollectorImpl<>( 630 () -> new long[1], 631 (a, t) -> { a[0] += mapper.applyAsLong(t); }, 632 (a, b) -> { a[0] += b[0]; return a; }, 633 a -> a[0], CH_NOID); 634 } 635 636 /** 637 * Returns a {@code Collector} that produces the sum of a double-valued 638 * function applied to the input elements. If no elements are present, 639 * the result is 0. 640 * 641 * <p>The sum returned can vary depending upon the order in which 642 * values are recorded, due to accumulated rounding error in 643 * addition of values of differing magnitudes. Values sorted by increasing 644 * absolute magnitude tend to yield more accurate results. If any recorded 645 * value is a {@code NaN} or the sum is at any point a {@code NaN} then the 646 * sum will be {@code NaN}. 647 * 648 * @param <T> the type of the input elements 649 * @param mapper a function extracting the property to be summed 650 * @return a {@code Collector} that produces the sum of a derived property 651 */ 652 public static <T> Collector<T, ?, Double> 653 summingDouble(ToDoubleFunction<? super T> mapper) { 654 /* 655 * In the arrays allocated for the collect operation, index 0 656 * holds the high-order bits of the running sum, index 1 holds 657 * the low-order bits of the sum computed via compensated 658 * summation, and index 2 holds the simple sum used to compute 659 * the proper result if the stream contains infinite values of 660 * the same sign. 661 */ 662 return new CollectorImpl<>( 663 () -> new double[3], 664 (a, t) -> { double val = mapper.applyAsDouble(t); 665 sumWithCompensation(a, val); 666 a[2] += val;}, 667 (a, b) -> { sumWithCompensation(a, b[0]); 668 a[2] += b[2]; 669 return sumWithCompensation(a, b[1]); }, 670 a -> computeFinalSum(a), 671 CH_NOID); 672 } 673 674 /** 675 * Incorporate a new double value using Kahan summation / 676 * compensation summation. 677 * 678 * High-order bits of the sum are in intermediateSum[0], low-order 679 * bits of the sum are in intermediateSum[1], any additional 680 * elements are application-specific. 681 * 682 * @param intermediateSum the high-order and low-order words of the intermediate sum 683 * @param value the name value to be included in the running sum 684 */ 685 static double[] sumWithCompensation(double[] intermediateSum, double value) { 686 double tmp = value - intermediateSum[1]; 687 double sum = intermediateSum[0]; 688 double velvel = sum + tmp; // Little wolf of rounding error 689 intermediateSum[1] = (velvel - sum) - tmp; 690 intermediateSum[0] = velvel; 691 return intermediateSum; 692 } 693 694 /** 695 * If the compensated sum is spuriously NaN from accumulating one 696 * or more same-signed infinite values, return the 697 * correctly-signed infinity stored in the simple sum. 698 */ 699 static double computeFinalSum(double[] summands) { 700 // Better error bounds to add both terms as the final sum 701 double tmp = summands[0] + summands[1]; 702 double simpleSum = summands[summands.length - 1]; 703 if (Double.isNaN(tmp) && Double.isInfinite(simpleSum)) 704 return simpleSum; 705 else 706 return tmp; 707 } 708 709 /** 710 * Returns a {@code Collector} that produces the arithmetic mean of an integer-valued 711 * function applied to the input elements. If no elements are present, 712 * the result is 0. 713 * 714 * @param <T> the type of the input elements 715 * @param mapper a function extracting the property to be summed 716 * @return a {@code Collector} that produces the sum of a derived property 717 */ 718 public static <T> Collector<T, ?, Double> 719 averagingInt(ToIntFunction<? super T> mapper) { 720 return new CollectorImpl<>( 721 () -> new long[2], 722 (a, t) -> { a[0] += mapper.applyAsInt(t); a[1]++; }, 723 (a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; }, 724 a -> (a[1] == 0) ? 0.0d : (double) a[0] / a[1], CH_NOID); 725 } 726 727 /** 728 * Returns a {@code Collector} that produces the arithmetic mean of a long-valued 729 * function applied to the input elements. If no elements are present, 730 * the result is 0. 731 * 732 * @param <T> the type of the input elements 733 * @param mapper a function extracting the property to be summed 734 * @return a {@code Collector} that produces the sum of a derived property 735 */ 736 public static <T> Collector<T, ?, Double> 737 averagingLong(ToLongFunction<? super T> mapper) { 738 return new CollectorImpl<>( 739 () -> new long[2], 740 (a, t) -> { a[0] += mapper.applyAsLong(t); a[1]++; }, 741 (a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; }, 742 a -> (a[1] == 0) ? 0.0d : (double) a[0] / a[1], CH_NOID); 743 } 744 745 /** 746 * Returns a {@code Collector} that produces the arithmetic mean of a double-valued 747 * function applied to the input elements. If no elements are present, 748 * the result is 0. 749 * 750 * <p>The average returned can vary depending upon the order in which 751 * values are recorded, due to accumulated rounding error in 752 * addition of values of differing magnitudes. Values sorted by increasing 753 * absolute magnitude tend to yield more accurate results. If any recorded 754 * value is a {@code NaN} or the sum is at any point a {@code NaN} then the 755 * average will be {@code NaN}. 756 * 757 * @implNote The {@code double} format can represent all 758 * consecutive integers in the range -2<sup>53</sup> to 759 * 2<sup>53</sup>. If the pipeline has more than 2<sup>53</sup> 760 * values, the divisor in the average computation will saturate at 761 * 2<sup>53</sup>, leading to additional numerical errors. 762 * 763 * @param <T> the type of the input elements 764 * @param mapper a function extracting the property to be summed 765 * @return a {@code Collector} that produces the sum of a derived property 766 */ 767 public static <T> Collector<T, ?, Double> 768 averagingDouble(ToDoubleFunction<? super T> mapper) { 769 /* 770 * In the arrays allocated for the collect operation, index 0 771 * holds the high-order bits of the running sum, index 1 holds 772 * the low-order bits of the sum computed via compensated 773 * summation, and index 2 holds the number of values seen. 774 */ 775 return new CollectorImpl<>( 776 () -> new double[4], 777 (a, t) -> { double val = mapper.applyAsDouble(t); sumWithCompensation(a, val); a[2]++; a[3]+= val;}, 778 (a, b) -> { sumWithCompensation(a, b[0]); sumWithCompensation(a, b[1]); a[2] += b[2]; a[3] += b[3]; return a; }, 779 a -> (a[2] == 0) ? 0.0d : (computeFinalSum(a) / a[2]), 780 CH_NOID); 781 } 782 783 /** 784 * Returns a {@code Collector} which performs a reduction of its 785 * input elements under a specified {@code BinaryOperator} using the 786 * provided identity. 787 * 788 * @apiNote 789 * The {@code reducing()} collectors are most useful when used in a 790 * multi-level reduction, downstream of {@code groupingBy} or 791 * {@code partitioningBy}. To perform a simple reduction on a stream, 792 * use {@link Stream#reduce(Object, BinaryOperator)}} instead. 793 * 794 * @param <T> element type for the input and output of the reduction 795 * @param identity the identity value for the reduction (also, the value 796 * that is returned when there are no input elements) 797 * @param op a {@code BinaryOperator<T>} used to reduce the input elements 798 * @return a {@code Collector} which implements the reduction operation 799 * 800 * @see #reducing(BinaryOperator) 801 * @see #reducing(Object, Function, BinaryOperator) 802 */ 803 public static <T> Collector<T, ?, T> 804 reducing(T identity, BinaryOperator<T> op) { 805 return new CollectorImpl<>( 806 boxSupplier(identity), 807 (a, t) -> { a[0] = op.apply(a[0], t); }, 808 (a, b) -> { a[0] = op.apply(a[0], b[0]); return a; }, 809 a -> a[0], 810 CH_NOID); 811 } 812 813 @SuppressWarnings("unchecked") 814 private static <T> Supplier<T[]> boxSupplier(T identity) { 815 return () -> (T[]) new Object[] { identity }; 816 } 817 818 /** 819 * Returns a {@code Collector} which performs a reduction of its 820 * input elements under a specified {@code BinaryOperator}. The result 821 * is described as an {@code Optional<T>}. 822 * 823 * @apiNote 824 * The {@code reducing()} collectors are most useful when used in a 825 * multi-level reduction, downstream of {@code groupingBy} or 826 * {@code partitioningBy}. To perform a simple reduction on a stream, 827 * use {@link Stream#reduce(BinaryOperator)} instead. 828 * 829 * <p>For example, given a stream of {@code Person}, to calculate tallest 830 * person in each city: 831 * <pre>{@code 832 * Comparator<Person> byHeight = Comparator.comparing(Person::getHeight); 833 * Map<City, Optional<Person>> tallestByCity 834 * = people.stream().collect(groupingBy(Person::getCity, reducing(BinaryOperator.maxBy(byHeight)))); 835 * }</pre> 836 * 837 * @param <T> element type for the input and output of the reduction 838 * @param op a {@code BinaryOperator<T>} used to reduce the input elements 839 * @return a {@code Collector} which implements the reduction operation 840 * 841 * @see #reducing(Object, BinaryOperator) 842 * @see #reducing(Object, Function, BinaryOperator) 843 */ 844 public static <T> Collector<T, ?, Optional<T>> 845 reducing(BinaryOperator<T> op) { 846 class OptionalBox implements Consumer<T> { 847 T value = null; 848 boolean present = false; 849 850 @Override 851 public void accept(T t) { 852 if (present) { 853 value = op.apply(value, t); 854 } 855 else { 856 value = t; 857 present = true; 858 } 859 } 860 } 861 862 return new CollectorImpl<T, OptionalBox, Optional<T>>( 863 OptionalBox::new, OptionalBox::accept, 864 (a, b) -> { if (b.present) a.accept(b.value); return a; }, 865 a -> Optional.ofNullable(a.value), CH_NOID); 866 } 867 868 /** 869 * Returns a {@code Collector} which performs a reduction of its 870 * input elements under a specified mapping function and 871 * {@code BinaryOperator}. This is a generalization of 872 * {@link #reducing(Object, BinaryOperator)} which allows a transformation 873 * of the elements before reduction. 874 * 875 * @apiNote 876 * The {@code reducing()} collectors are most useful when used in a 877 * multi-level reduction, downstream of {@code groupingBy} or 878 * {@code partitioningBy}. To perform a simple map-reduce on a stream, 879 * use {@link Stream#map(Function)} and {@link Stream#reduce(Object, BinaryOperator)} 880 * instead. 881 * 882 * <p>For example, given a stream of {@code Person}, to calculate the longest 883 * last name of residents in each city: 884 * <pre>{@code 885 * Comparator<String> byLength = Comparator.comparing(String::length); 886 * Map<City, String> longestLastNameByCity 887 * = people.stream().collect(groupingBy(Person::getCity, 888 * reducing("", Person::getLastName, BinaryOperator.maxBy(byLength)))); 889 * }</pre> 890 * 891 * @param <T> the type of the input elements 892 * @param <U> the type of the mapped values 893 * @param identity the identity value for the reduction (also, the value 894 * that is returned when there are no input elements) 895 * @param mapper a mapping function to apply to each input value 896 * @param op a {@code BinaryOperator<U>} used to reduce the mapped values 897 * @return a {@code Collector} implementing the map-reduce operation 898 * 899 * @see #reducing(Object, BinaryOperator) 900 * @see #reducing(BinaryOperator) 901 */ 902 public static <T, U> 903 Collector<T, ?, U> reducing(U identity, 904 Function<? super T, ? extends U> mapper, 905 BinaryOperator<U> op) { 906 return new CollectorImpl<>( 907 boxSupplier(identity), 908 (a, t) -> { a[0] = op.apply(a[0], mapper.apply(t)); }, 909 (a, b) -> { a[0] = op.apply(a[0], b[0]); return a; }, 910 a -> a[0], CH_NOID); 911 } 912 913 /** 914 * Returns a {@code Collector} implementing a "group by" operation on 915 * input elements of type {@code T}, grouping elements according to a 916 * classification function, and returning the results in a {@code Map}. 917 * 918 * <p>The classification function maps elements to some key type {@code K}. 919 * The collector produces a {@code Map<K, List<T>>} whose keys are the 920 * values resulting from applying the classification function to the input 921 * elements, and whose corresponding values are {@code List}s containing the 922 * input elements which map to the associated key under the classification 923 * function. 924 * 925 * <p>There are no guarantees on the type, mutability, serializability, or 926 * thread-safety of the {@code Map} or {@code List} objects returned. 927 * @implSpec 928 * This produces a result similar to: 929 * <pre>{@code 930 * groupingBy(classifier, toList()); 931 * }</pre> 932 * 933 * @implNote 934 * The returned {@code Collector} is not concurrent. For parallel stream 935 * pipelines, the {@code combiner} function operates by merging the keys 936 * from one map into another, which can be an expensive operation. If 937 * preservation of the order in which elements appear in the resulting {@code Map} 938 * collector is not required, using {@link #groupingByConcurrent(Function)} 939 * may offer better parallel performance. 940 * 941 * @param <T> the type of the input elements 942 * @param <K> the type of the keys 943 * @param classifier the classifier function mapping input elements to keys 944 * @return a {@code Collector} implementing the group-by operation 945 * 946 * @see #groupingBy(Function, Collector) 947 * @see #groupingBy(Function, Supplier, Collector) 948 * @see #groupingByConcurrent(Function) 949 */ 950 public static <T, K> Collector<T, ?, Map<K, List<T>>> 951 groupingBy(Function<? super T, ? extends K> classifier) { 952 return groupingBy(classifier, toList()); 953 } 954 955 /** 956 * Returns a {@code Collector} implementing a cascaded "group by" operation 957 * on input elements of type {@code T}, grouping elements according to a 958 * classification function, and then performing a reduction operation on 959 * the values associated with a given key using the specified downstream 960 * {@code Collector}. 961 * 962 * <p>The classification function maps elements to some key type {@code K}. 963 * The downstream collector operates on elements of type {@code T} and 964 * produces a result of type {@code D}. The resulting collector produces a 965 * {@code Map<K, D>}. 966 * 967 * <p>There are no guarantees on the type, mutability, 968 * serializability, or thread-safety of the {@code Map} returned. 969 * 970 * <p>For example, to compute the set of last names of people in each city: 971 * <pre>{@code 972 * Map<City, Set<String>> namesByCity 973 * = people.stream().collect(groupingBy(Person::getCity, 974 * mapping(Person::getLastName, toSet()))); 975 * }</pre> 976 * 977 * @implNote 978 * The returned {@code Collector} is not concurrent. For parallel stream 979 * pipelines, the {@code combiner} function operates by merging the keys 980 * from one map into another, which can be an expensive operation. If 981 * preservation of the order in which elements are presented to the downstream 982 * collector is not required, using {@link #groupingByConcurrent(Function, Collector)} 983 * may offer better parallel performance. 984 * 985 * @param <T> the type of the input elements 986 * @param <K> the type of the keys 987 * @param <A> the intermediate accumulation type of the downstream collector 988 * @param <D> the result type of the downstream reduction 989 * @param classifier a classifier function mapping input elements to keys 990 * @param downstream a {@code Collector} implementing the downstream reduction 991 * @return a {@code Collector} implementing the cascaded group-by operation 992 * @see #groupingBy(Function) 993 * 994 * @see #groupingBy(Function, Supplier, Collector) 995 * @see #groupingByConcurrent(Function, Collector) 996 */ 997 public static <T, K, A, D> 998 Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier, 999 Collector<? super T, A, D> downstream) { 1000 return groupingBy(classifier, HashMap::new, downstream); 1001 } 1002 1003 /** 1004 * Returns a {@code Collector} implementing a cascaded "group by" operation 1005 * on input elements of type {@code T}, grouping elements according to a 1006 * classification function, and then performing a reduction operation on 1007 * the values associated with a given key using the specified downstream 1008 * {@code Collector}. The {@code Map} produced by the Collector is created 1009 * with the supplied factory function. 1010 * 1011 * <p>The classification function maps elements to some key type {@code K}. 1012 * The downstream collector operates on elements of type {@code T} and 1013 * produces a result of type {@code D}. The resulting collector produces a 1014 * {@code Map<K, D>}. 1015 * 1016 * <p>For example, to compute the set of last names of people in each city, 1017 * where the city names are sorted: 1018 * <pre>{@code 1019 * Map<City, Set<String>> namesByCity 1020 * = people.stream().collect(groupingBy(Person::getCity, TreeMap::new, 1021 * mapping(Person::getLastName, toSet()))); 1022 * }</pre> 1023 * 1024 * @implNote 1025 * The returned {@code Collector} is not concurrent. For parallel stream 1026 * pipelines, the {@code combiner} function operates by merging the keys 1027 * from one map into another, which can be an expensive operation. If 1028 * preservation of the order in which elements are presented to the downstream 1029 * collector is not required, using {@link #groupingByConcurrent(Function, Supplier, Collector)} 1030 * may offer better parallel performance. 1031 * 1032 * @param <T> the type of the input elements 1033 * @param <K> the type of the keys 1034 * @param <A> the intermediate accumulation type of the downstream collector 1035 * @param <D> the result type of the downstream reduction 1036 * @param <M> the type of the resulting {@code Map} 1037 * @param classifier a classifier function mapping input elements to keys 1038 * @param downstream a {@code Collector} implementing the downstream reduction 1039 * @param mapFactory a function which, when called, produces a new empty 1040 * {@code Map} of the desired type 1041 * @return a {@code Collector} implementing the cascaded group-by operation 1042 * 1043 * @see #groupingBy(Function, Collector) 1044 * @see #groupingBy(Function) 1045 * @see #groupingByConcurrent(Function, Supplier, Collector) 1046 */ 1047 public static <T, K, D, A, M extends Map<K, D>> 1048 Collector<T, ?, M> groupingBy(Function<? super T, ? extends K> classifier, 1049 Supplier<M> mapFactory, 1050 Collector<? super T, A, D> downstream) { 1051 Supplier<A> downstreamSupplier = downstream.supplier(); 1052 BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator(); 1053 BiConsumer<Map<K, A>, T> accumulator = (m, t) -> { 1054 K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key"); 1055 A container = m.computeIfAbsent(key, k -> downstreamSupplier.get()); 1056 downstreamAccumulator.accept(container, t); 1057 }; 1058 BinaryOperator<Map<K, A>> merger = Collectors.<K, A, Map<K, A>>mapMerger(downstream.combiner()); 1059 @SuppressWarnings("unchecked") 1060 Supplier<Map<K, A>> mangledFactory = (Supplier<Map<K, A>>) mapFactory; 1061 1062 if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) { 1063 return new CollectorImpl<>(mangledFactory, accumulator, merger, CH_ID); 1064 } 1065 else { 1066 @SuppressWarnings("unchecked") 1067 Function<A, A> downstreamFinisher = (Function<A, A>) downstream.finisher(); 1068 Function<Map<K, A>, M> finisher = intermediate -> { 1069 intermediate.replaceAll((k, v) -> downstreamFinisher.apply(v)); 1070 @SuppressWarnings("unchecked") 1071 M castResult = (M) intermediate; 1072 return castResult; 1073 }; 1074 return new CollectorImpl<>(mangledFactory, accumulator, merger, finisher, CH_NOID); 1075 } 1076 } 1077 1078 /** 1079 * Returns a concurrent {@code Collector} implementing a "group by" 1080 * operation on input elements of type {@code T}, grouping elements 1081 * according to a classification function. 1082 * 1083 * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and 1084 * {@link Collector.Characteristics#UNORDERED unordered} Collector. 1085 * 1086 * <p>The classification function maps elements to some key type {@code K}. 1087 * The collector produces a {@code ConcurrentMap<K, List<T>>} whose keys are the 1088 * values resulting from applying the classification function to the input 1089 * elements, and whose corresponding values are {@code List}s containing the 1090 * input elements which map to the associated key under the classification 1091 * function. 1092 * 1093 * <p>There are no guarantees on the type, mutability, or serializability 1094 * of the {@code ConcurrentMap} or {@code List} objects returned, or of the 1095 * thread-safety of the {@code List} objects returned. 1096 * @implSpec 1097 * This produces a result similar to: 1098 * <pre>{@code 1099 * groupingByConcurrent(classifier, toList()); 1100 * }</pre> 1101 * 1102 * @param <T> the type of the input elements 1103 * @param <K> the type of the keys 1104 * @param classifier a classifier function mapping input elements to keys 1105 * @return a concurrent, unordered {@code Collector} implementing the group-by operation 1106 * 1107 * @see #groupingBy(Function) 1108 * @see #groupingByConcurrent(Function, Collector) 1109 * @see #groupingByConcurrent(Function, Supplier, Collector) 1110 */ 1111 public static <T, K> 1112 Collector<T, ?, ConcurrentMap<K, List<T>>> 1113 groupingByConcurrent(Function<? super T, ? extends K> classifier) { 1114 return groupingByConcurrent(classifier, ConcurrentHashMap::new, toList()); 1115 } 1116 1117 /** 1118 * Returns a concurrent {@code Collector} implementing a cascaded "group by" 1119 * operation on input elements of type {@code T}, grouping elements 1120 * according to a classification function, and then performing a reduction 1121 * operation on the values associated with a given key using the specified 1122 * downstream {@code Collector}. 1123 * 1124 * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and 1125 * {@link Collector.Characteristics#UNORDERED unordered} Collector. 1126 * 1127 * <p>The classification function maps elements to some key type {@code K}. 1128 * The downstream collector operates on elements of type {@code T} and 1129 * produces a result of type {@code D}. The resulting collector produces a 1130 * {@code Map<K, D>}. 1131 * 1132 * <p>There are no guarantees on the type, mutability, or serializability 1133 * of the {@code ConcurrentMap} returned. 1134 * 1135 * <p>For example, to compute the set of last names of people in each city, 1136 * where the city names are sorted: 1137 * <pre>{@code 1138 * ConcurrentMap<City, Set<String>> namesByCity 1139 * = people.stream().collect(groupingByConcurrent(Person::getCity, 1140 * mapping(Person::getLastName, toSet()))); 1141 * }</pre> 1142 * 1143 * @param <T> the type of the input elements 1144 * @param <K> the type of the keys 1145 * @param <A> the intermediate accumulation type of the downstream collector 1146 * @param <D> the result type of the downstream reduction 1147 * @param classifier a classifier function mapping input elements to keys 1148 * @param downstream a {@code Collector} implementing the downstream reduction 1149 * @return a concurrent, unordered {@code Collector} implementing the cascaded group-by operation 1150 * 1151 * @see #groupingBy(Function, Collector) 1152 * @see #groupingByConcurrent(Function) 1153 * @see #groupingByConcurrent(Function, Supplier, Collector) 1154 */ 1155 public static <T, K, A, D> 1156 Collector<T, ?, ConcurrentMap<K, D>> groupingByConcurrent(Function<? super T, ? extends K> classifier, 1157 Collector<? super T, A, D> downstream) { 1158 return groupingByConcurrent(classifier, ConcurrentHashMap::new, downstream); 1159 } 1160 1161 /** 1162 * Returns a concurrent {@code Collector} implementing a cascaded "group by" 1163 * operation on input elements of type {@code T}, grouping elements 1164 * according to a classification function, and then performing a reduction 1165 * operation on the values associated with a given key using the specified 1166 * downstream {@code Collector}. The {@code ConcurrentMap} produced by the 1167 * Collector is created with the supplied factory function. 1168 * 1169 * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and 1170 * {@link Collector.Characteristics#UNORDERED unordered} Collector. 1171 * 1172 * <p>The classification function maps elements to some key type {@code K}. 1173 * The downstream collector operates on elements of type {@code T} and 1174 * produces a result of type {@code D}. The resulting collector produces a 1175 * {@code Map<K, D>}. 1176 * 1177 * <p>For example, to compute the set of last names of people in each city, 1178 * where the city names are sorted: 1179 * <pre>{@code 1180 * ConcurrentMap<City, Set<String>> namesByCity 1181 * = people.stream().collect(groupingBy(Person::getCity, ConcurrentSkipListMap::new, 1182 * mapping(Person::getLastName, toSet()))); 1183 * }</pre> 1184 * 1185 * 1186 * @param <T> the type of the input elements 1187 * @param <K> the type of the keys 1188 * @param <A> the intermediate accumulation type of the downstream collector 1189 * @param <D> the result type of the downstream reduction 1190 * @param <M> the type of the resulting {@code ConcurrentMap} 1191 * @param classifier a classifier function mapping input elements to keys 1192 * @param downstream a {@code Collector} implementing the downstream reduction 1193 * @param mapFactory a function which, when called, produces a new empty 1194 * {@code ConcurrentMap} of the desired type 1195 * @return a concurrent, unordered {@code Collector} implementing the cascaded group-by operation 1196 * 1197 * @see #groupingByConcurrent(Function) 1198 * @see #groupingByConcurrent(Function, Collector) 1199 * @see #groupingBy(Function, Supplier, Collector) 1200 */ 1201 public static <T, K, A, D, M extends ConcurrentMap<K, D>> 1202 Collector<T, ?, M> groupingByConcurrent(Function<? super T, ? extends K> classifier, 1203 Supplier<M> mapFactory, 1204 Collector<? super T, A, D> downstream) { 1205 Supplier<A> downstreamSupplier = downstream.supplier(); 1206 BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator(); 1207 BinaryOperator<ConcurrentMap<K, A>> merger = Collectors.<K, A, ConcurrentMap<K, A>>mapMerger(downstream.combiner()); 1208 @SuppressWarnings("unchecked") 1209 Supplier<ConcurrentMap<K, A>> mangledFactory = (Supplier<ConcurrentMap<K, A>>) mapFactory; 1210 BiConsumer<ConcurrentMap<K, A>, T> accumulator; 1211 if (downstream.characteristics().contains(Collector.Characteristics.CONCURRENT)) { 1212 accumulator = (m, t) -> { 1213 K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key"); 1214 A resultContainer = m.computeIfAbsent(key, k -> downstreamSupplier.get()); 1215 downstreamAccumulator.accept(resultContainer, t); 1216 }; 1217 } 1218 else { 1219 accumulator = (m, t) -> { 1220 K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key"); 1221 A resultContainer = m.computeIfAbsent(key, k -> downstreamSupplier.get()); 1222 synchronized (resultContainer) { 1223 downstreamAccumulator.accept(resultContainer, t); 1224 } 1225 }; 1226 } 1227 1228 if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) { 1229 return new CollectorImpl<>(mangledFactory, accumulator, merger, CH_CONCURRENT_ID); 1230 } 1231 else { 1232 @SuppressWarnings("unchecked") 1233 Function<A, A> downstreamFinisher = (Function<A, A>) downstream.finisher(); 1234 Function<ConcurrentMap<K, A>, M> finisher = intermediate -> { 1235 intermediate.replaceAll((k, v) -> downstreamFinisher.apply(v)); 1236 @SuppressWarnings("unchecked") 1237 M castResult = (M) intermediate; 1238 return castResult; 1239 }; 1240 return new CollectorImpl<>(mangledFactory, accumulator, merger, finisher, CH_CONCURRENT_NOID); 1241 } 1242 } 1243 1244 /** 1245 * Returns a {@code Collector} which partitions the input elements according 1246 * to a {@code Predicate}, and organizes them into a 1247 * {@code Map<Boolean, List<T>>}. 1248 * 1249 * There are no guarantees on the type, mutability, 1250 * serializability, or thread-safety of the {@code Map} or {@code List} 1251 * returned. 1252 * 1253 * @param <T> the type of the input elements 1254 * @param predicate a predicate used for classifying input elements 1255 * @return a {@code Collector} implementing the partitioning operation 1256 * 1257 * @see #partitioningBy(Predicate, Collector) 1258 */ 1259 public static <T> 1260 Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate) { 1261 return partitioningBy(predicate, toList()); 1262 } 1263 1264 /** 1265 * Returns a {@code Collector} which partitions the input elements according 1266 * to a {@code Predicate}, reduces the values in each partition according to 1267 * another {@code Collector}, and organizes them into a 1268 * {@code Map<Boolean, D>} whose values are the result of the downstream 1269 * reduction. 1270 * 1271 * <p>There are no guarantees on the type, mutability, 1272 * serializability, or thread-safety of the {@code Map} returned. 1273 * 1274 * @param <T> the type of the input elements 1275 * @param <A> the intermediate accumulation type of the downstream collector 1276 * @param <D> the result type of the downstream reduction 1277 * @param predicate a predicate used for classifying input elements 1278 * @param downstream a {@code Collector} implementing the downstream 1279 * reduction 1280 * @return a {@code Collector} implementing the cascaded partitioning 1281 * operation 1282 * 1283 * @see #partitioningBy(Predicate) 1284 */ 1285 public static <T, D, A> 1286 Collector<T, ?, Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate, 1287 Collector<? super T, A, D> downstream) { 1288 BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator(); 1289 BiConsumer<Partition<A>, T> accumulator = (result, t) -> 1290 downstreamAccumulator.accept(predicate.test(t) ? result.forTrue : result.forFalse, t); 1291 BinaryOperator<A> op = downstream.combiner(); 1292 BinaryOperator<Partition<A>> merger = (left, right) -> 1293 new Partition<>(op.apply(left.forTrue, right.forTrue), 1294 op.apply(left.forFalse, right.forFalse)); 1295 Supplier<Partition<A>> supplier = () -> 1296 new Partition<>(downstream.supplier().get(), 1297 downstream.supplier().get()); 1298 if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) { 1299 return new CollectorImpl<>(supplier, accumulator, merger, CH_ID); 1300 } 1301 else { 1302 Function<Partition<A>, Map<Boolean, D>> finisher = par -> 1303 new Partition<>(downstream.finisher().apply(par.forTrue), 1304 downstream.finisher().apply(par.forFalse)); 1305 return new CollectorImpl<>(supplier, accumulator, merger, finisher, CH_NOID); 1306 } 1307 } 1308 1309 /** 1310 * Returns a {@code Collector} that accumulates elements into a 1311 * {@code Map} whose keys and values are the result of applying the provided 1312 * mapping functions to the input elements. 1313 * 1314 * <p>If the mapped keys contains duplicates (according to 1315 * {@link Object#equals(Object)}), an {@code IllegalStateException} is 1316 * thrown when the collection operation is performed. If the mapped keys 1317 * may have duplicates, use {@link #toMap(Function, Function, BinaryOperator)} 1318 * instead. 1319 * 1320 * <p>There are no guarantees on the type, mutability, serializability, 1321 * or thread-safety of the {@code Map} returned. 1322 * 1323 * @apiNote 1324 * It is common for either the key or the value to be the input elements. 1325 * In this case, the utility method 1326 * {@link java.util.function.Function#identity()} may be helpful. 1327 * For example, the following produces a {@code Map} mapping 1328 * students to their grade point average: 1329 * <pre>{@code 1330 * Map<Student, Double> studentToGPA 1331 * students.stream().collect(toMap(Function.identity(), 1332 * student -> computeGPA(student))); 1333 * }</pre> 1334 * And the following produces a {@code Map} mapping a unique identifier to 1335 * students: 1336 * <pre>{@code 1337 * Map<String, Student> studentIdToStudent 1338 * students.stream().collect(toMap(Student::getId, 1339 * Function.identity()); 1340 * }</pre> 1341 * 1342 * @implNote 1343 * The returned {@code Collector} is not concurrent. For parallel stream 1344 * pipelines, the {@code combiner} function operates by merging the keys 1345 * from one map into another, which can be an expensive operation. If it is 1346 * not required that results are inserted into the {@code Map} in encounter 1347 * order, using {@link #toConcurrentMap(Function, Function)} 1348 * may offer better parallel performance. 1349 * 1350 * @param <T> the type of the input elements 1351 * @param <K> the output type of the key mapping function 1352 * @param <U> the output type of the value mapping function 1353 * @param keyMapper a mapping function to produce keys 1354 * @param valueMapper a mapping function to produce values 1355 * @return a {@code Collector} which collects elements into a {@code Map} 1356 * whose keys and values are the result of applying mapping functions to 1357 * the input elements 1358 * 1359 * @see #toMap(Function, Function, BinaryOperator) 1360 * @see #toMap(Function, Function, BinaryOperator, Supplier) 1361 * @see #toConcurrentMap(Function, Function) 1362 */ 1363 public static <T, K, U> 1364 Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper, 1365 Function<? super T, ? extends U> valueMapper) { 1366 return new CollectorImpl<>(HashMap::new, 1367 uniqKeysMapAccumulator(keyMapper, valueMapper), 1368 uniqKeysMapMerger(), 1369 CH_ID); 1370 } 1371 1372 /** 1373 * Returns a {@code Collector} that accumulates elements into a 1374 * {@code Map} whose keys and values are the result of applying the provided 1375 * mapping functions to the input elements. 1376 * 1377 * <p>If the mapped 1378 * keys contains duplicates (according to {@link Object#equals(Object)}), 1379 * the value mapping function is applied to each equal element, and the 1380 * results are merged using the provided merging function. 1381 * 1382 * <p>There are no guarantees on the type, mutability, serializability, 1383 * or thread-safety of the {@code Map} returned. 1384 * 1385 * @apiNote 1386 * There are multiple ways to deal with collisions between multiple elements 1387 * mapping to the same key. The other forms of {@code toMap} simply use 1388 * a merge function that throws unconditionally, but you can easily write 1389 * more flexible merge policies. For example, if you have a stream 1390 * of {@code Person}, and you want to produce a "phone book" mapping name to 1391 * address, but it is possible that two persons have the same name, you can 1392 * do as follows to gracefully deals with these collisions, and produce a 1393 * {@code Map} mapping names to a concatenated list of addresses: 1394 * <pre>{@code 1395 * Map<String, String> phoneBook 1396 * people.stream().collect(toMap(Person::getName, 1397 * Person::getAddress, 1398 * (s, a) -> s + ", " + a)); 1399 * }</pre> 1400 * 1401 * @implNote 1402 * The returned {@code Collector} is not concurrent. For parallel stream 1403 * pipelines, the {@code combiner} function operates by merging the keys 1404 * from one map into another, which can be an expensive operation. If it is 1405 * not required that results are merged into the {@code Map} in encounter 1406 * order, using {@link #toConcurrentMap(Function, Function, BinaryOperator)} 1407 * may offer better parallel performance. 1408 * 1409 * @param <T> the type of the input elements 1410 * @param <K> the output type of the key mapping function 1411 * @param <U> the output type of the value mapping function 1412 * @param keyMapper a mapping function to produce keys 1413 * @param valueMapper a mapping function to produce values 1414 * @param mergeFunction a merge function, used to resolve collisions between 1415 * values associated with the same key, as supplied 1416 * to {@link Map#merge(Object, Object, BiFunction)} 1417 * @return a {@code Collector} which collects elements into a {@code Map} 1418 * whose keys are the result of applying a key mapping function to the input 1419 * elements, and whose values are the result of applying a value mapping 1420 * function to all input elements equal to the key and combining them 1421 * using the merge function 1422 * 1423 * @see #toMap(Function, Function) 1424 * @see #toMap(Function, Function, BinaryOperator, Supplier) 1425 * @see #toConcurrentMap(Function, Function, BinaryOperator) 1426 */ 1427 public static <T, K, U> 1428 Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper, 1429 Function<? super T, ? extends U> valueMapper, 1430 BinaryOperator<U> mergeFunction) { 1431 return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new); 1432 } 1433 1434 /** 1435 * Returns a {@code Collector} that accumulates elements into a 1436 * {@code Map} whose keys and values are the result of applying the provided 1437 * mapping functions to the input elements. 1438 * 1439 * <p>If the mapped 1440 * keys contains duplicates (according to {@link Object#equals(Object)}), 1441 * the value mapping function is applied to each equal element, and the 1442 * results are merged using the provided merging function. The {@code Map} 1443 * is created by a provided supplier function. 1444 * 1445 * @implNote 1446 * The returned {@code Collector} is not concurrent. For parallel stream 1447 * pipelines, the {@code combiner} function operates by merging the keys 1448 * from one map into another, which can be an expensive operation. If it is 1449 * not required that results are merged into the {@code Map} in encounter 1450 * order, using {@link #toConcurrentMap(Function, Function, BinaryOperator, Supplier)} 1451 * may offer better parallel performance. 1452 * 1453 * @param <T> the type of the input elements 1454 * @param <K> the output type of the key mapping function 1455 * @param <U> the output type of the value mapping function 1456 * @param <M> the type of the resulting {@code Map} 1457 * @param keyMapper a mapping function to produce keys 1458 * @param valueMapper a mapping function to produce values 1459 * @param mergeFunction a merge function, used to resolve collisions between 1460 * values associated with the same key, as supplied 1461 * to {@link Map#merge(Object, Object, BiFunction)} 1462 * @param mapSupplier a function which returns a new, empty {@code Map} into 1463 * which the results will be inserted 1464 * @return a {@code Collector} which collects elements into a {@code Map} 1465 * whose keys are the result of applying a key mapping function to the input 1466 * elements, and whose values are the result of applying a value mapping 1467 * function to all input elements equal to the key and combining them 1468 * using the merge function 1469 * 1470 * @see #toMap(Function, Function) 1471 * @see #toMap(Function, Function, BinaryOperator) 1472 * @see #toConcurrentMap(Function, Function, BinaryOperator, Supplier) 1473 */ 1474 public static <T, K, U, M extends Map<K, U>> 1475 Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper, 1476 Function<? super T, ? extends U> valueMapper, 1477 BinaryOperator<U> mergeFunction, 1478 Supplier<M> mapSupplier) { 1479 BiConsumer<M, T> accumulator 1480 = (map, element) -> map.merge(keyMapper.apply(element), 1481 valueMapper.apply(element), mergeFunction); 1482 return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_ID); 1483 } 1484 1485 /** 1486 * Returns a concurrent {@code Collector} that accumulates elements into a 1487 * {@code ConcurrentMap} whose keys and values are the result of applying 1488 * the provided mapping functions to the input elements. 1489 * 1490 * <p>If the mapped keys contains duplicates (according to 1491 * {@link Object#equals(Object)}), an {@code IllegalStateException} is 1492 * thrown when the collection operation is performed. If the mapped keys 1493 * may have duplicates, use 1494 * {@link #toConcurrentMap(Function, Function, BinaryOperator)} instead. 1495 * 1496 * <p>There are no guarantees on the type, mutability, or serializability 1497 * of the {@code ConcurrentMap} returned. 1498 * 1499 * @apiNote 1500 * It is common for either the key or the value to be the input elements. 1501 * In this case, the utility method 1502 * {@link java.util.function.Function#identity()} may be helpful. 1503 * For example, the following produces a {@code Map} mapping 1504 * students to their grade point average: 1505 * <pre>{@code 1506 * Map<Student, Double> studentToGPA 1507 * students.stream().collect(toMap(Function.identity(), 1508 * student -> computeGPA(student))); 1509 * }</pre> 1510 * And the following produces a {@code Map} mapping a unique identifier to 1511 * students: 1512 * <pre>{@code 1513 * Map<String, Student> studentIdToStudent 1514 * students.stream().collect(toConcurrentMap(Student::getId, 1515 * Function.identity()); 1516 * }</pre> 1517 * 1518 * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and 1519 * {@link Collector.Characteristics#UNORDERED unordered} Collector. 1520 * 1521 * @param <T> the type of the input elements 1522 * @param <K> the output type of the key mapping function 1523 * @param <U> the output type of the value mapping function 1524 * @param keyMapper the mapping function to produce keys 1525 * @param valueMapper the mapping function to produce values 1526 * @return a concurrent, unordered {@code Collector} which collects elements into a 1527 * {@code ConcurrentMap} whose keys are the result of applying a key mapping 1528 * function to the input elements, and whose values are the result of 1529 * applying a value mapping function to the input elements 1530 * 1531 * @see #toMap(Function, Function) 1532 * @see #toConcurrentMap(Function, Function, BinaryOperator) 1533 * @see #toConcurrentMap(Function, Function, BinaryOperator, Supplier) 1534 */ 1535 public static <T, K, U> 1536 Collector<T, ?, ConcurrentMap<K,U>> toConcurrentMap(Function<? super T, ? extends K> keyMapper, 1537 Function<? super T, ? extends U> valueMapper) { 1538 return new CollectorImpl<>(ConcurrentHashMap::new, 1539 uniqKeysMapAccumulator(keyMapper, valueMapper), 1540 uniqKeysMapMerger(), 1541 CH_CONCURRENT_ID); 1542 } 1543 1544 /** 1545 * Returns a concurrent {@code Collector} that accumulates elements into a 1546 * {@code ConcurrentMap} whose keys and values are the result of applying 1547 * the provided mapping functions to the input elements. 1548 * 1549 * <p>If the mapped keys contains duplicates (according to {@link Object#equals(Object)}), 1550 * the value mapping function is applied to each equal element, and the 1551 * results are merged using the provided merging function. 1552 * 1553 * <p>There are no guarantees on the type, mutability, or serializability 1554 * of the {@code ConcurrentMap} returned. 1555 * 1556 * @apiNote 1557 * There are multiple ways to deal with collisions between multiple elements 1558 * mapping to the same key. The other forms of {@code toConcurrentMap} simply use 1559 * a merge function that throws unconditionally, but you can easily write 1560 * more flexible merge policies. For example, if you have a stream 1561 * of {@code Person}, and you want to produce a "phone book" mapping name to 1562 * address, but it is possible that two persons have the same name, you can 1563 * do as follows to gracefully deals with these collisions, and produce a 1564 * {@code Map} mapping names to a concatenated list of addresses: 1565 * <pre>{@code 1566 * Map<String, String> phoneBook 1567 * people.stream().collect(toConcurrentMap(Person::getName, 1568 * Person::getAddress, 1569 * (s, a) -> s + ", " + a)); 1570 * }</pre> 1571 * 1572 * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and 1573 * {@link Collector.Characteristics#UNORDERED unordered} Collector. 1574 * 1575 * @param <T> the type of the input elements 1576 * @param <K> the output type of the key mapping function 1577 * @param <U> the output type of the value mapping function 1578 * @param keyMapper a mapping function to produce keys 1579 * @param valueMapper a mapping function to produce values 1580 * @param mergeFunction a merge function, used to resolve collisions between 1581 * values associated with the same key, as supplied 1582 * to {@link Map#merge(Object, Object, BiFunction)} 1583 * @return a concurrent, unordered {@code Collector} which collects elements into a 1584 * {@code ConcurrentMap} whose keys are the result of applying a key mapping 1585 * function to the input elements, and whose values are the result of 1586 * applying a value mapping function to all input elements equal to the key 1587 * and combining them using the merge function 1588 * 1589 * @see #toConcurrentMap(Function, Function) 1590 * @see #toConcurrentMap(Function, Function, BinaryOperator, Supplier) 1591 * @see #toMap(Function, Function, BinaryOperator) 1592 */ 1593 public static <T, K, U> 1594 Collector<T, ?, ConcurrentMap<K,U>> 1595 toConcurrentMap(Function<? super T, ? extends K> keyMapper, 1596 Function<? super T, ? extends U> valueMapper, 1597 BinaryOperator<U> mergeFunction) { 1598 return toConcurrentMap(keyMapper, valueMapper, mergeFunction, ConcurrentHashMap::new); 1599 } 1600 1601 /** 1602 * Returns a concurrent {@code Collector} that accumulates elements into a 1603 * {@code ConcurrentMap} whose keys and values are the result of applying 1604 * the provided mapping functions to the input elements. 1605 * 1606 * <p>If the mapped keys contains duplicates (according to {@link Object#equals(Object)}), 1607 * the value mapping function is applied to each equal element, and the 1608 * results are merged using the provided merging function. The 1609 * {@code ConcurrentMap} is created by a provided supplier function. 1610 * 1611 * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and 1612 * {@link Collector.Characteristics#UNORDERED unordered} Collector. 1613 * 1614 * @param <T> the type of the input elements 1615 * @param <K> the output type of the key mapping function 1616 * @param <U> the output type of the value mapping function 1617 * @param <M> the type of the resulting {@code ConcurrentMap} 1618 * @param keyMapper a mapping function to produce keys 1619 * @param valueMapper a mapping function to produce values 1620 * @param mergeFunction a merge function, used to resolve collisions between 1621 * values associated with the same key, as supplied 1622 * to {@link Map#merge(Object, Object, BiFunction)} 1623 * @param mapSupplier a function which returns a new, empty {@code Map} into 1624 * which the results will be inserted 1625 * @return a concurrent, unordered {@code Collector} which collects elements into a 1626 * {@code ConcurrentMap} whose keys are the result of applying a key mapping 1627 * function to the input elements, and whose values are the result of 1628 * applying a value mapping function to all input elements equal to the key 1629 * and combining them using the merge function 1630 * 1631 * @see #toConcurrentMap(Function, Function) 1632 * @see #toConcurrentMap(Function, Function, BinaryOperator) 1633 * @see #toMap(Function, Function, BinaryOperator, Supplier) 1634 */ 1635 public static <T, K, U, M extends ConcurrentMap<K, U>> 1636 Collector<T, ?, M> toConcurrentMap(Function<? super T, ? extends K> keyMapper, 1637 Function<? super T, ? extends U> valueMapper, 1638 BinaryOperator<U> mergeFunction, 1639 Supplier<M> mapSupplier) { 1640 BiConsumer<M, T> accumulator 1641 = (map, element) -> map.merge(keyMapper.apply(element), 1642 valueMapper.apply(element), mergeFunction); 1643 return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_CONCURRENT_ID); 1644 } 1645 1646 /** 1647 * Returns a {@code Collector} which applies an {@code int}-producing 1648 * mapping function to each input element, and returns summary statistics 1649 * for the resulting values. 1650 * 1651 * @param <T> the type of the input elements 1652 * @param mapper a mapping function to apply to each element 1653 * @return a {@code Collector} implementing the summary-statistics reduction 1654 * 1655 * @see #summarizingDouble(ToDoubleFunction) 1656 * @see #summarizingLong(ToLongFunction) 1657 */ 1658 public static <T> 1659 Collector<T, ?, IntSummaryStatistics> summarizingInt(ToIntFunction<? super T> mapper) { 1660 return new CollectorImpl<T, IntSummaryStatistics, IntSummaryStatistics>( 1661 IntSummaryStatistics::new, 1662 (r, t) -> r.accept(mapper.applyAsInt(t)), 1663 (l, r) -> { l.combine(r); return l; }, CH_ID); 1664 } 1665 1666 /** 1667 * Returns a {@code Collector} which applies an {@code long}-producing 1668 * mapping function to each input element, and returns summary statistics 1669 * for the resulting values. 1670 * 1671 * @param <T> the type of the input elements 1672 * @param mapper the mapping function to apply to each element 1673 * @return a {@code Collector} implementing the summary-statistics reduction 1674 * 1675 * @see #summarizingDouble(ToDoubleFunction) 1676 * @see #summarizingInt(ToIntFunction) 1677 */ 1678 public static <T> 1679 Collector<T, ?, LongSummaryStatistics> summarizingLong(ToLongFunction<? super T> mapper) { 1680 return new CollectorImpl<T, LongSummaryStatistics, LongSummaryStatistics>( 1681 LongSummaryStatistics::new, 1682 (r, t) -> r.accept(mapper.applyAsLong(t)), 1683 (l, r) -> { l.combine(r); return l; }, CH_ID); 1684 } 1685 1686 /** 1687 * Returns a {@code Collector} which applies an {@code double}-producing 1688 * mapping function to each input element, and returns summary statistics 1689 * for the resulting values. 1690 * 1691 * @param <T> the type of the input elements 1692 * @param mapper a mapping function to apply to each element 1693 * @return a {@code Collector} implementing the summary-statistics reduction 1694 * 1695 * @see #summarizingLong(ToLongFunction) 1696 * @see #summarizingInt(ToIntFunction) 1697 */ 1698 public static <T> 1699 Collector<T, ?, DoubleSummaryStatistics> summarizingDouble(ToDoubleFunction<? super T> mapper) { 1700 return new CollectorImpl<T, DoubleSummaryStatistics, DoubleSummaryStatistics>( 1701 DoubleSummaryStatistics::new, 1702 (r, t) -> r.accept(mapper.applyAsDouble(t)), 1703 (l, r) -> { l.combine(r); return l; }, CH_ID); 1704 } 1705 1706 /** 1707 * Implementation class used by partitioningBy. 1708 */ 1709 private static final class Partition<T> 1710 extends AbstractMap<Boolean, T> 1711 implements Map<Boolean, T> { 1712 final T forTrue; 1713 final T forFalse; 1714 1715 Partition(T forTrue, T forFalse) { 1716 this.forTrue = forTrue; 1717 this.forFalse = forFalse; 1718 } 1719 1720 @Override 1721 public Set<Map.Entry<Boolean, T>> entrySet() { 1722 return new AbstractSet<>() { 1723 @Override 1724 public Iterator<Map.Entry<Boolean, T>> iterator() { 1725 Map.Entry<Boolean, T> falseEntry = new SimpleImmutableEntry<>(false, forFalse); 1726 Map.Entry<Boolean, T> trueEntry = new SimpleImmutableEntry<>(true, forTrue); 1727 return List.of(falseEntry, trueEntry).iterator(); 1728 } 1729 1730 @Override 1731 public int size() { 1732 return 2; 1733 } 1734 }; 1735 } 1736 } 1737 }