62 * <p>The following are examples of using the predefined {@code Collector} |
65 * <p>The following are examples of using the predefined {@code Collector} |
63 * implementations in {@link Collectors} with the {@code Stream} API to perform |
66 * implementations in {@link Collectors} with the {@code Stream} API to perform |
64 * mutable reduction tasks: |
67 * mutable reduction tasks: |
65 * |
68 * |
66 * <pre>{@code |
69 * <pre>{@code |
67 * // Accumulate elements into a List |
70 * // Accumulate names into a List |
68 * List<Person> list = people.collect(Collectors.toList()); |
71 * List<String> list = people.stream().map(Person::getName).collect(Collectors.toList()); |
69 * |
72 * |
70 * // Accumulate elements into a TreeSet |
73 * // Accumulate names into a TreeSet |
71 * List<Person> list = people.collect(Collectors.toCollection(TreeSet::new)); |
74 * Set<String> list = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new)); |
72 * |
75 * |
73 * // Convert elements to strings and concatenate them, separated by commas |
76 * // Convert elements to strings and concatenate them, separated by commas |
74 * String joined = stream.map(Object::toString) |
77 * String joined = things.stream() |
75 * .collect(Collectors.toStringJoiner(", ")) |
78 * .map(Object::toString) |
76 * .toString(); |
79 * .collect(Collectors.joining(", ")); |
77 * |
80 * |
78 * // Find highest-paid employee |
81 * // Find highest-paid employee |
79 * Employee highestPaid = employees.stream() |
82 * Employee highestPaid = employees.stream() |
80 * .collect(Collectors.maxBy(Comparator.comparing(Employee::getSalary))); |
83 * .collect(Collectors.maxBy(Comparator.comparing(Employee::getSalary))) |
|
84 * .get(); |
81 * |
85 * |
82 * // Group employees by department |
86 * // Group employees by department |
83 * Map<Department, List<Employee>> byDept |
87 * Map<Department, List<Employee>> byDept |
84 * = employees.stream() |
88 * = employees.stream() |
85 * .collect(Collectors.groupingBy(Employee::getDepartment)); |
89 * .collect(Collectors.groupingBy(Employee::getDepartment)); |
86 * |
90 * |
87 * // Find highest-paid employee by department |
91 * // Find highest-paid employee by department |
88 * Map<Department, Employee> highestPaidByDept |
92 * Map<Department, Optional<Employee>> highestPaidByDept |
89 * = employees.stream() |
93 * = employees.stream() |
90 * .collect(Collectors.groupingBy(Employee::getDepartment, |
94 * .collect(Collectors.groupingBy(Employee::getDepartment, |
91 * Collectors.maxBy(Comparator.comparing(Employee::getSalary)))); |
95 * Collectors.maxBy(Comparator.comparing(Employee::getSalary)))); |
92 * |
96 * |
93 * // Partition students into passing and failing |
97 * // Partition students into passing and failing |
94 * Map<Boolean, List<Student>> passingFailing = |
98 * Map<Boolean, List<Student>> passingFailing = |
95 * students.stream() |
99 * students.stream() |
96 * .collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD); |
100 * .collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD)); |
97 * |
101 * |
98 * }</pre> |
102 * }</pre> |
99 * |
103 * |
100 * TODO explanation of parallel collection |
104 * TODO explanation of parallel collection |
101 * |
105 * |
102 * @since 1.8 |
106 * @since 1.8 |
103 */ |
107 */ |
104 public final class Collectors { |
108 public final class Collectors { |
105 |
109 |
106 private static final Set<Collector.Characteristics> CH_CONCURRENT |
110 static final Set<Collector.Characteristics> CH_CONCURRENT_ID |
107 = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.CONCURRENT, |
111 = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.CONCURRENT, |
108 Collector.Characteristics.STRICTLY_MUTATIVE, |
112 Collector.Characteristics.UNORDERED, |
|
113 Collector.Characteristics.IDENTITY_FINISH)); |
|
114 static final Set<Collector.Characteristics> CH_CONCURRENT_NOID |
|
115 = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.CONCURRENT, |
109 Collector.Characteristics.UNORDERED)); |
116 Collector.Characteristics.UNORDERED)); |
110 private static final Set<Collector.Characteristics> CH_STRICT |
117 static final Set<Collector.Characteristics> CH_ID |
111 = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.STRICTLY_MUTATIVE)); |
118 = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH)); |
112 private static final Set<Collector.Characteristics> CH_STRICT_UNORDERED |
119 static final Set<Collector.Characteristics> CH_UNORDERED_ID |
113 = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.STRICTLY_MUTATIVE, |
120 = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.UNORDERED, |
114 Collector.Characteristics.UNORDERED)); |
121 Collector.Characteristics.IDENTITY_FINISH)); |
|
122 static final Set<Collector.Characteristics> CH_NOID = Collections.emptySet(); |
115 |
123 |
116 private Collectors() { } |
124 private Collectors() { } |
117 |
125 |
118 /** |
126 /** |
119 * Returns a merge function, suitable for use in |
127 * Returns a merge function, suitable for use in |
122 * throws {@code IllegalStateException}. This can be used to enforce the |
130 * throws {@code IllegalStateException}. This can be used to enforce the |
123 * assumption that the elements being collected are distinct. |
131 * assumption that the elements being collected are distinct. |
124 * |
132 * |
125 * @param <T> the type of input arguments to the merge function |
133 * @param <T> the type of input arguments to the merge function |
126 * @return a merge function which always throw {@code IllegalStateException} |
134 * @return a merge function which always throw {@code IllegalStateException} |
127 * |
135 */ |
128 * @see #firstWinsMerger() |
136 private static <T> BinaryOperator<T> throwingMerger() { |
129 * @see #lastWinsMerger() |
|
130 */ |
|
131 public static <T> BinaryOperator<T> throwingMerger() { |
|
132 return (u,v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); }; |
137 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 } |
138 } |
164 |
139 |
165 /** |
140 /** |
166 * Simple implementation class for {@code Collector}. |
141 * Simple implementation class for {@code Collector}. |
167 * |
142 * |
168 * @param <T> the type of elements to be collected |
143 * @param <T> the type of elements to be collected |
169 * @param <R> the type of the result |
144 * @param <R> the type of the result |
170 */ |
145 */ |
171 private static final class CollectorImpl<T, R> implements Collector<T,R> { |
146 static class CollectorImpl<T, A, R> implements Collector<T, A, R> { |
172 private final Supplier<R> resultSupplier; |
147 private final Supplier<A> supplier; |
173 private final BiFunction<R, T, R> accumulator; |
148 private final BiConsumer<A, T> accumulator; |
174 private final BinaryOperator<R> combiner; |
149 private final BinaryOperator<A> combiner; |
|
150 private final Function<A, R> finisher; |
175 private final Set<Characteristics> characteristics; |
151 private final Set<Characteristics> characteristics; |
176 |
152 |
177 CollectorImpl(Supplier<R> resultSupplier, |
153 CollectorImpl(Supplier<A> supplier, |
178 BiFunction<R, T, R> accumulator, |
154 BiConsumer<A, T> accumulator, |
179 BinaryOperator<R> combiner, |
155 BinaryOperator<A> combiner, |
|
156 Function<A,R> finisher, |
180 Set<Characteristics> characteristics) { |
157 Set<Characteristics> characteristics) { |
181 this.resultSupplier = resultSupplier; |
158 this.supplier = supplier; |
182 this.accumulator = accumulator; |
159 this.accumulator = accumulator; |
183 this.combiner = combiner; |
160 this.combiner = combiner; |
|
161 this.finisher = finisher; |
184 this.characteristics = characteristics; |
162 this.characteristics = characteristics; |
185 } |
163 } |
186 |
164 |
187 CollectorImpl(Supplier<R> resultSupplier, |
165 CollectorImpl(Supplier<A> supplier, |
188 BiFunction<R, T, R> accumulator, |
166 BiConsumer<A, T> accumulator, |
189 BinaryOperator<R> combiner) { |
167 BinaryOperator<A> combiner, |
190 this(resultSupplier, accumulator, combiner, Collections.emptySet()); |
168 Set<Characteristics> characteristics) { |
|
169 this(supplier, accumulator, combiner, i -> (R) i, characteristics); |
191 } |
170 } |
192 |
171 |
193 @Override |
172 @Override |
194 public BiFunction<R, T, R> accumulator() { |
173 public BiConsumer<A, T> accumulator() { |
195 return accumulator; |
174 return accumulator; |
196 } |
175 } |
197 |
176 |
198 @Override |
177 @Override |
199 public Supplier<R> resultSupplier() { |
178 public Supplier<A> supplier() { |
200 return resultSupplier; |
179 return supplier; |
201 } |
180 } |
202 |
181 |
203 @Override |
182 @Override |
204 public BinaryOperator<R> combiner() { |
183 public BinaryOperator<A> combiner() { |
205 return combiner; |
184 return combiner; |
|
185 } |
|
186 |
|
187 @Override |
|
188 public Function<A, R> finisher() { |
|
189 return finisher; |
206 } |
190 } |
207 |
191 |
208 @Override |
192 @Override |
209 public Set<Characteristics> characteristics() { |
193 public Set<Characteristics> characteristics() { |
210 return characteristics; |
194 return characteristics; |
284 * @param <T> the type of the input elements |
241 * @param <T> the type of the input elements |
285 * @return a {@code Collector} which collects all the input elements into a |
242 * @return a {@code Collector} which collects all the input elements into a |
286 * {@code Set} |
243 * {@code Set} |
287 */ |
244 */ |
288 public static <T> |
245 public static <T> |
289 Collector<T, Set<T>> toSet() { |
246 Collector<T, ?, Set<T>> toSet() { |
290 return new CollectorImpl<>((Supplier<Set<T>>) HashSet::new, |
247 return new CollectorImpl<>((Supplier<Set<T>>) HashSet::new, Set::add, |
291 (r, t) -> { r.add(t); return r; }, |
248 (left, right) -> { left.addAll(right); return left; }, |
292 (r1, r2) -> { r1.addAll(r2); return r1; }, |
249 CH_UNORDERED_ID); |
293 CH_STRICT_UNORDERED); |
|
294 } |
250 } |
295 |
251 |
296 /** |
252 /** |
297 * Returns a {@code Collector} that concatenates the input elements into a |
253 * Returns a {@code Collector} that concatenates the input elements into a |
298 * new {@link StringBuilder}. |
254 * {@code String}, in encounter order. |
299 * |
255 * |
300 * @return a {@code Collector} which collects String elements into a |
256 * @return a {@code Collector} that concatenates the input elements into a |
301 * {@code StringBuilder}, in encounter order |
257 * {@code String}, in encounter order |
302 */ |
258 */ |
303 public static Collector<String, StringBuilder> toStringBuilder() { |
259 public static Collector<CharSequence, ?, String> joining() { |
304 return new CollectorImpl<>(StringBuilder::new, |
260 return new CollectorImpl<CharSequence, StringBuilder, String>( |
305 (r, t) -> { r.append(t); return r; }, |
261 StringBuilder::new, StringBuilder::append, |
306 (r1, r2) -> { r1.append(r2); return r1; }, |
262 (r1, r2) -> { r1.append(r2); return r1; }, |
307 CH_STRICT); |
263 StringBuilder::toString, CH_NOID); |
308 } |
264 } |
309 |
265 |
310 /** |
266 /** |
311 * Returns a {@code Collector} that concatenates the input elements into a |
267 * Returns a {@code Collector} that concatenates the input elements, |
312 * new {@link StringJoiner}, using the specified delimiter. |
268 * separated by the specified delimiter, in encounter order. |
313 * |
269 * |
314 * @param delimiter the delimiter to be used between each element |
270 * @param delimiter the delimiter to be used between each element |
315 * @return A {@code Collector} which collects String elements into a |
271 * @return A {@code Collector} which concatenates CharSequence elements, |
316 * {@code StringJoiner}, in encounter order |
272 * separated by the specified delimiter, in encounter order |
317 */ |
273 */ |
318 public static Collector<CharSequence, StringJoiner> toStringJoiner(CharSequence delimiter) { |
274 public static Collector<CharSequence, ?, String> joining(CharSequence delimiter) { |
319 BinaryOperator<StringJoiner> merger = (sj, other) -> { |
275 return joining(delimiter, "", ""); |
320 if (other.length() > 0) |
276 } |
321 sj.add(other.toString()); |
277 |
322 return sj; |
278 /** |
323 }; |
279 * Returns a {@code Collector} that concatenates the input elements, |
324 return new CollectorImpl<>(() -> new StringJoiner(delimiter), |
280 * separated by the specified delimiter, with the specified prefix and |
325 (r, t) -> { r.add(t); return r; }, |
281 * suffix, in encounter order. |
326 merger, CH_STRICT); |
282 * |
|
283 * @param delimiter the delimiter to be used between each element |
|
284 * @param prefix the sequence of characters to be used at the beginning |
|
285 * of the joined result |
|
286 * @param suffix the sequence of characters to be used at the end |
|
287 * of the joined result |
|
288 * @return A {@code Collector} which concatenates CharSequence elements, |
|
289 * separated by the specified delimiter, in encounter order |
|
290 */ |
|
291 public static Collector<CharSequence, ?, String> joining(CharSequence delimiter, |
|
292 CharSequence prefix, |
|
293 CharSequence suffix) { |
|
294 return new CollectorImpl<>( |
|
295 () -> new StringJoiner(delimiter, prefix, suffix), |
|
296 StringJoiner::add, StringJoiner::merge, |
|
297 StringJoiner::toString, CH_NOID); |
327 } |
298 } |
328 |
299 |
329 /** |
300 /** |
330 * {@code BinaryOperator<Map>} that merges the contents of its right |
301 * {@code BinaryOperator<Map>} that merges the contents of its right |
331 * argument into its left argument, using the provided merge function to |
302 * argument into its left argument, using the provided merge function to |
346 return m1; |
317 return m1; |
347 }; |
318 }; |
348 } |
319 } |
349 |
320 |
350 /** |
321 /** |
351 * Adapts a {@code Collector<U,R>} to a {@code Collector<T,R>} by applying |
322 * Adapts a {@code Collector} accepting elements of type {@code U} to one |
352 * a mapping function to each input element before accumulation. |
323 * accepting elements of type {@code T} by applying a mapping function to |
|
324 * each input element before accumulation. |
353 * |
325 * |
354 * @apiNote |
326 * @apiNote |
355 * The {@code mapping()} collectors are most useful when used in a |
327 * The {@code mapping()} collectors are most useful when used in a |
356 * multi-level reduction, downstream of {@code groupingBy} or |
328 * multi-level reduction, such as downstream of a {@code groupingBy} or |
357 * {@code partitioningBy}. For example, given a stream of |
329 * {@code partitioningBy}. For example, given a stream of |
358 * {@code Person}, to accumulate the set of last names in each city: |
330 * {@code Person}, to accumulate the set of last names in each city: |
359 * <pre>{@code |
331 * <pre>{@code |
360 * Map<City, Set<String>> lastNamesByCity |
332 * Map<City, Set<String>> lastNamesByCity |
361 * = people.stream().collect(groupingBy(Person::getCity, |
333 * = people.stream().collect(groupingBy(Person::getCity, |
362 * mapping(Person::getLastName, toSet()))); |
334 * mapping(Person::getLastName, toSet()))); |
363 * }</pre> |
335 * }</pre> |
364 * |
336 * |
365 * @param <T> the type of the input elements |
337 * @param <T> the type of the input elements |
366 * @param <U> type of elements accepted by downstream collector |
338 * @param <U> type of elements accepted by downstream collector |
|
339 * @param <A> intermediate accumulation type of the downstream collector |
367 * @param <R> result type of collector |
340 * @param <R> result type of collector |
368 * @param mapper a function to be applied to the input elements |
341 * @param mapper a function to be applied to the input elements |
369 * @param downstream a collector which will accept mapped values |
342 * @param downstream a collector which will accept mapped values |
370 * @return a collector which applies the mapping function to the input |
343 * @return a collector which applies the mapping function to the input |
371 * elements and provides the mapped results to the downstream collector |
344 * elements and provides the mapped results to the downstream collector |
372 */ |
345 */ |
373 public static <T, U, R> Collector<T, R> |
346 public static <T, U, A, R> |
374 mapping(Function<? super T, ? extends U> mapper, Collector<? super U, R> downstream) { |
347 Collector<T, ?, R> mapping(Function<? super T, ? extends U> mapper, |
375 BiFunction<R, ? super U, R> downstreamAccumulator = downstream.accumulator(); |
348 Collector<? super U, A, R> downstream) { |
376 return new CollectorImpl<>(downstream.resultSupplier(), |
349 BiConsumer<A, ? super U> downstreamAccumulator = downstream.accumulator(); |
377 (r, t) -> downstreamAccumulator.apply(r, mapper.apply(t)), |
350 return new CollectorImpl<>(downstream.supplier(), |
378 downstream.combiner(), downstream.characteristics()); |
351 (r, t) -> downstreamAccumulator.accept(r, mapper.apply(t)), |
379 } |
352 downstream.combiner(), downstream.finisher(), |
380 |
353 downstream.characteristics()); |
381 /** |
354 } |
382 * Returns a {@code Collector<T, Long>} that counts the number of input |
355 |
383 * elements. |
356 /** |
|
357 * Returns a {@code Collector} accepting elements of type {@code T} that |
|
358 * counts the number of input elements. If no elements are present, the |
|
359 * result is 0. |
384 * |
360 * |
385 * @implSpec |
361 * @implSpec |
386 * This produces a result equivalent to: |
362 * This produces a result equivalent to: |
387 * <pre>{@code |
363 * <pre>{@code |
388 * reducing(0L, e -> 1L, Long::sum) |
364 * reducing(0L, e -> 1L, Long::sum) |
389 * }</pre> |
365 * }</pre> |
390 * |
366 * |
391 * @param <T> the type of the input elements |
367 * @param <T> the type of the input elements |
392 * @return a {@code Collector} that counts the input elements |
368 * @return a {@code Collector} that counts the input elements |
393 */ |
369 */ |
394 public static <T> Collector<T, Long> |
370 public static <T> Collector<T, ?, Long> |
395 counting() { |
371 counting() { |
396 return reducing(0L, e -> 1L, Long::sum); |
372 return reducing(0L, e -> 1L, Long::sum); |
397 } |
373 } |
398 |
374 |
399 /** |
375 /** |
400 * Returns a {@code Collector<T, T>} that produces the minimal element |
376 * Returns a {@code Collector} that produces the minimal element according |
401 * according to a given {@code Comparator}. |
377 * to a given {@code Comparator}, described as an {@code Optional<T>}. |
402 * |
378 * |
403 * @implSpec |
379 * @implSpec |
404 * This produces a result equivalent to: |
380 * This produces a result equivalent to: |
405 * <pre>{@code |
381 * <pre>{@code |
406 * reducing(BinaryOperator.minBy(comparator)) |
382 * reducing(BinaryOperator.minBy(comparator)) |
427 * |
403 * |
428 * @param <T> the type of the input elements |
404 * @param <T> the type of the input elements |
429 * @param comparator a {@code Comparator} for comparing elements |
405 * @param comparator a {@code Comparator} for comparing elements |
430 * @return a {@code Collector} that produces the maximal value |
406 * @return a {@code Collector} that produces the maximal value |
431 */ |
407 */ |
432 public static <T> Collector<T, T> |
408 public static <T> Collector<T, ?, Optional<T>> |
433 maxBy(Comparator<? super T> comparator) { |
409 maxBy(Comparator<? super T> comparator) { |
434 return reducing(BinaryOperator.maxBy(comparator)); |
410 return reducing(BinaryOperator.maxBy(comparator)); |
435 } |
411 } |
436 |
412 |
437 /** |
413 /** |
438 * Returns a {@code Collector<T, Long>} that produces the sum of a |
414 * Returns a {@code Collector} that produces the sum of a integer-valued |
439 * long-valued function applied to the input element. |
415 * function applied to the input elements. If no elements are present, |
440 * |
416 * the result is 0. |
441 * @implSpec |
|
442 * This produces a result equivalent to: |
|
443 * <pre>{@code |
|
444 * reducing(0L, mapper, Long::sum) |
|
445 * }</pre> |
|
446 * |
417 * |
447 * @param <T> the type of the input elements |
418 * @param <T> the type of the input elements |
448 * @param mapper a function extracting the property to be summed |
419 * @param mapper a function extracting the property to be summed |
449 * @return a {@code Collector} that produces the sum of a derived property |
420 * @return a {@code Collector} that produces the sum of a derived property |
450 */ |
421 */ |
451 public static <T> Collector<T, Long> |
422 public static <T> Collector<T, ?, Integer> |
452 sumBy(Function<? super T, Long> mapper) { |
423 summingInt(ToIntFunction<? super T> mapper) { |
453 return reducing(0L, mapper, Long::sum); |
424 return new CollectorImpl<T, int[], Integer>( |
454 } |
425 () -> new int[1], |
455 |
426 (a, t) -> { a[0] += mapper.applyAsInt(t); }, |
456 /** |
427 (a, b) -> { a[0] += b[0]; return a; }, |
457 * Returns a {@code Collector<T,T>} which performs a reduction of its |
428 a -> a[0], CH_NOID); |
458 * input elements under a specified {@code BinaryOperator}. |
429 } |
|
430 |
|
431 /** |
|
432 * Returns a {@code Collector} that produces the sum of a long-valued |
|
433 * function applied to the input elements. If no elements are present, |
|
434 * the result is 0. |
|
435 * |
|
436 * @param <T> the type of the input elements |
|
437 * @param mapper a function extracting the property to be summed |
|
438 * @return a {@code Collector} that produces the sum of a derived property |
|
439 */ |
|
440 public static <T> Collector<T, ?, Long> |
|
441 summingLong(ToLongFunction<? super T> mapper) { |
|
442 return new CollectorImpl<T, long[], Long>( |
|
443 () -> new long[1], |
|
444 (a, t) -> { a[0] += mapper.applyAsLong(t); }, |
|
445 (a, b) -> { a[0] += b[0]; return a; }, |
|
446 a -> a[0], CH_NOID); |
|
447 } |
|
448 |
|
449 /** |
|
450 * Returns a {@code Collector} that produces the sum of a double-valued |
|
451 * function applied to the input elements. If no elements are present, |
|
452 * the result is 0. |
|
453 * |
|
454 * <p>The sum returned can vary depending upon the order in which |
|
455 * values are recorded, due to accumulated rounding error in |
|
456 * addition of values of differing magnitudes. Values sorted by increasing |
|
457 * absolute magnitude tend to yield more accurate results. If any recorded |
|
458 * value is a {@code NaN} or the sum is at any point a {@code NaN} then the |
|
459 * sum will be {@code NaN}. |
|
460 * |
|
461 * @param <T> the type of the input elements |
|
462 * @param mapper a function extracting the property to be summed |
|
463 * @return a {@code Collector} that produces the sum of a derived property |
|
464 */ |
|
465 public static <T> Collector<T, ?, Double> |
|
466 summingDouble(ToDoubleFunction<? super T> mapper) { |
|
467 return new CollectorImpl<T, double[], Double>( |
|
468 () -> new double[1], |
|
469 (a, t) -> { a[0] += mapper.applyAsDouble(t); }, |
|
470 (a, b) -> { a[0] += b[0]; return a; }, |
|
471 a -> a[0], CH_NOID); |
|
472 } |
|
473 |
|
474 /** |
|
475 * Returns a {@code Collector} that produces the arithmetic mean of an integer-valued |
|
476 * function applied to the input elements. If no elements are present, |
|
477 * the result is 0. |
|
478 * |
|
479 * @param <T> the type of the input elements |
|
480 * @param mapper a function extracting the property to be summed |
|
481 * @return a {@code Collector} that produces the sum of a derived property |
|
482 */ |
|
483 public static <T> Collector<T, ?, Double> |
|
484 averagingInt(ToIntFunction<? super T> mapper) { |
|
485 return new CollectorImpl<T, long[], Double>( |
|
486 () -> new long[2], |
|
487 (a, t) -> { a[0] += mapper.applyAsInt(t); a[1]++; }, |
|
488 (a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; }, |
|
489 a -> (a[1] == 0) ? 0.0d : (double) a[0] / a[1], CH_NOID); |
|
490 } |
|
491 |
|
492 /** |
|
493 * Returns a {@code Collector} that produces the arithmetic mean of a long-valued |
|
494 * function applied to the input elements. If no elements are present, |
|
495 * the result is 0. |
|
496 * |
|
497 * @param <T> the type of the input elements |
|
498 * @param mapper a function extracting the property to be summed |
|
499 * @return a {@code Collector} that produces the sum of a derived property |
|
500 */ |
|
501 public static <T> Collector<T, ?, Double> |
|
502 averagingLong(ToLongFunction<? super T> mapper) { |
|
503 return new CollectorImpl<T, long[], Double>( |
|
504 () -> new long[2], |
|
505 (a, t) -> { a[0] += mapper.applyAsLong(t); a[1]++; }, |
|
506 (a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; }, |
|
507 a -> (a[1] == 0) ? 0.0d : (double) a[0] / a[1], CH_NOID); |
|
508 } |
|
509 |
|
510 /** |
|
511 * Returns a {@code Collector} that produces the arithmetic mean of a double-valued |
|
512 * function applied to the input elements. If no elements are present, |
|
513 * the result is 0. |
|
514 * |
|
515 * <p>The average returned can vary depending upon the order in which |
|
516 * values are recorded, due to accumulated rounding error in |
|
517 * addition of values of differing magnitudes. Values sorted by increasing |
|
518 * absolute magnitude tend to yield more accurate results. If any recorded |
|
519 * value is a {@code NaN} or the sum is at any point a {@code NaN} then the |
|
520 * average will be {@code NaN}. |
|
521 * |
|
522 * @param <T> the type of the input elements |
|
523 * @param mapper a function extracting the property to be summed |
|
524 * @return a {@code Collector} that produces the sum of a derived property |
|
525 */ |
|
526 public static <T> Collector<T, ?, Double> |
|
527 averagingDouble(ToDoubleFunction<? super T> mapper) { |
|
528 return new CollectorImpl<T, double[], Double>( |
|
529 () -> new double[2], |
|
530 (a, t) -> { a[0] += mapper.applyAsDouble(t); a[1]++; }, |
|
531 (a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; }, |
|
532 a -> (a[1] == 0) ? 0.0d : a[0] / a[1], CH_NOID); |
|
533 } |
|
534 |
|
535 /** |
|
536 * Returns a {@code Collector} which performs a reduction of its |
|
537 * input elements under a specified {@code BinaryOperator} using the |
|
538 * provided identity. |
|
539 * |
|
540 * @apiNote |
|
541 * The {@code reducing()} collectors are most useful when used in a |
|
542 * multi-level reduction, downstream of {@code groupingBy} or |
|
543 * {@code partitioningBy}. To perform a simple reduction on a stream, |
|
544 * use {@link Stream#reduce(Object, BinaryOperator)}} instead. |
|
545 * |
|
546 * @param <T> element type for the input and output of the reduction |
|
547 * @param identity the identity value for the reduction (also, the value |
|
548 * that is returned when there are no input elements) |
|
549 * @param op a {@code BinaryOperator<T>} used to reduce the input elements |
|
550 * @return a {@code Collector} which implements the reduction operation |
|
551 * |
|
552 * @see #reducing(BinaryOperator) |
|
553 * @see #reducing(Object, Function, BinaryOperator) |
|
554 */ |
|
555 public static <T> Collector<T, ?, T> |
|
556 reducing(T identity, BinaryOperator<T> op) { |
|
557 return new CollectorImpl<>( |
|
558 boxSupplier(identity), |
|
559 (a, t) -> { a[0] = op.apply(a[0], t); }, |
|
560 (a, b) -> { a[0] = op.apply(a[0], b[0]); return a; }, |
|
561 a -> a[0], |
|
562 CH_NOID); |
|
563 } |
|
564 |
|
565 @SuppressWarnings("unchecked") |
|
566 private static <T> Supplier<T[]> boxSupplier(T identity) { |
|
567 return () -> (T[]) new Object[] { identity }; |
|
568 } |
|
569 |
|
570 /** |
|
571 * Returns a {@code Collector} which performs a reduction of its |
|
572 * input elements under a specified {@code BinaryOperator}. The result |
|
573 * is described as an {@code Optional<T>}. |
459 * |
574 * |
460 * @apiNote |
575 * @apiNote |
461 * The {@code reducing()} collectors are most useful when used in a |
576 * The {@code reducing()} collectors are most useful when used in a |
462 * multi-level reduction, downstream of {@code groupingBy} or |
577 * multi-level reduction, downstream of {@code groupingBy} or |
463 * {@code partitioningBy}. To perform a simple reduction on a stream, |
578 * {@code partitioningBy}. To perform a simple reduction on a stream, |
464 * use {@link Stream#reduce(BinaryOperator)} instead. |
579 * use {@link Stream#reduce(BinaryOperator)} instead. |
465 * |
580 * |
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 |
581 * <p>For example, given a stream of {@code Person}, to calculate tallest |
491 * person in each city: |
582 * person in each city: |
492 * <pre>{@code |
583 * <pre>{@code |
493 * Comparator<Person> byHeight = Comparator.comparing(Person::getHeight); |
584 * Comparator<Person> byHeight = Comparator.comparing(Person::getHeight); |
494 * BinaryOperator<Person> tallerOf = BinaryOperator.greaterOf(byHeight); |
|
495 * Map<City, Person> tallestByCity |
585 * Map<City, Person> tallestByCity |
496 * = people.stream().collect(groupingBy(Person::getCity, reducing(tallerOf))); |
586 * = people.stream().collect(groupingBy(Person::getCity, reducing(BinaryOperator.maxBy(byHeight)))); |
497 * }</pre> |
|
498 * |
|
499 * @implSpec |
|
500 * The default implementation is equivalent to: |
|
501 * <pre>{@code |
|
502 * reducing(null, op); |
|
503 * }</pre> |
587 * }</pre> |
504 * |
588 * |
505 * @param <T> element type for the input and output of the reduction |
589 * @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 |
590 * @param op a {@code BinaryOperator<T>} used to reduce the input elements |
507 * @return a {@code Collector} which implements the reduction operation |
591 * @return a {@code Collector} which implements the reduction operation |
508 * |
592 * |
509 * @see #reducing(Object, BinaryOperator) |
593 * @see #reducing(Object, BinaryOperator) |
510 * @see #reducing(Object, Function, BinaryOperator) |
594 * @see #reducing(Object, Function, BinaryOperator) |
511 */ |
595 */ |
512 public static <T> Collector<T, T> |
596 public static <T> Collector<T, ?, Optional<T>> |
513 reducing(BinaryOperator<T> op) { |
597 reducing(BinaryOperator<T> op) { |
514 return reducing(null, op); |
598 class OptionalBox implements Consumer<T> { |
515 } |
599 T value = null; |
516 |
600 boolean present = false; |
517 /** |
601 |
518 * Returns a {@code Collector<T,U>} which performs a reduction of its |
602 @Override |
|
603 public void accept(T t) { |
|
604 if (present) { |
|
605 value = op.apply(value, t); |
|
606 } |
|
607 else { |
|
608 value = t; |
|
609 present = true; |
|
610 } |
|
611 } |
|
612 } |
|
613 |
|
614 return new CollectorImpl<T, OptionalBox, Optional<T>>( |
|
615 OptionalBox::new, OptionalBox::accept, |
|
616 (a, b) -> { if (b.present) a.accept(b.value); return a; }, |
|
617 a -> Optional.ofNullable(a.value), CH_NOID); |
|
618 } |
|
619 |
|
620 /** |
|
621 * Returns a {@code Collector} which performs a reduction of its |
519 * input elements under a specified mapping function and |
622 * input elements under a specified mapping function and |
520 * {@code BinaryOperator}. This is a generalization of |
623 * {@code BinaryOperator}. This is a generalization of |
521 * {@link #reducing(Object, BinaryOperator)} which allows a transformation |
624 * {@link #reducing(Object, BinaryOperator)} which allows a transformation |
522 * of the elements before reduction. |
625 * of the elements before reduction. |
523 * |
626 * |
524 * @apiNote |
627 * @apiNote |
525 * The {@code reducing()} collectors are most useful when used in a |
628 * The {@code reducing()} collectors are most useful when used in a |
526 * multi-level reduction, downstream of {@code groupingBy} or |
629 * multi-level reduction, downstream of {@code groupingBy} or |
527 * {@code partitioningBy}. To perform a simple reduction on a stream, |
630 * {@code partitioningBy}. To perform a simple map-reduce on a stream, |
528 * use {@link Stream#reduce(BinaryOperator)} instead. |
631 * use {@link Stream#map(Function)} and {@link Stream#reduce(Object, BinaryOperator)} |
|
632 * instead. |
529 * |
633 * |
530 * <p>For example, given a stream of {@code Person}, to calculate the longest |
634 * <p>For example, given a stream of {@code Person}, to calculate the longest |
531 * last name of residents in each city: |
635 * last name of residents in each city: |
532 * <pre>{@code |
636 * <pre>{@code |
533 * Comparator<String> byLength = Comparator.comparing(String::length); |
637 * Comparator<String> byLength = Comparator.comparing(String::length); |
534 * BinaryOperator<String> longerOf = BinaryOperator.greaterOf(byLength); |
|
535 * Map<City, String> longestLastNameByCity |
638 * Map<City, String> longestLastNameByCity |
536 * = people.stream().collect(groupingBy(Person::getCity, |
639 * = people.stream().collect(groupingBy(Person::getCity, |
537 * reducing(Person::getLastName, longerOf))); |
640 * reducing(Person::getLastName, BinaryOperator.maxBy(byLength)))); |
538 * }</pre> |
641 * }</pre> |
539 * |
642 * |
540 * @param <T> the type of the input elements |
643 * @param <T> the type of the input elements |
541 * @param <U> the type of the mapped values |
644 * @param <U> the type of the mapped values |
542 * @param identity the identity value for the reduction (also, the value |
645 * @param identity the identity value for the reduction (also, the value |
663 * |
770 * |
664 * @see #groupingBy(Function, Collector) |
771 * @see #groupingBy(Function, Collector) |
665 * @see #groupingBy(Function) |
772 * @see #groupingBy(Function) |
666 * @see #groupingByConcurrent(Function, Supplier, Collector) |
773 * @see #groupingByConcurrent(Function, Supplier, Collector) |
667 */ |
774 */ |
668 public static <T, K, D, M extends Map<K, D>> |
775 public static <T, K, D, A, M extends Map<K, D>> |
669 Collector<T, M> groupingBy(Function<? super T, ? extends K> classifier, |
776 Collector<T, ?, M> groupingBy(Function<? super T, ? extends K> classifier, |
670 Supplier<M> mapFactory, |
777 Supplier<M> mapFactory, |
671 Collector<? super T, D> downstream) { |
778 Collector<? super T, A, D> downstream) { |
672 Supplier<D> downstreamSupplier = downstream.resultSupplier(); |
779 Supplier<A> downstreamSupplier = downstream.supplier(); |
673 BiFunction<D, ? super T, D> downstreamAccumulator = downstream.accumulator(); |
780 BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator(); |
674 BiFunction<M, T, M> accumulator = (m, t) -> { |
781 BiConsumer<Map<K, A>, T> accumulator = (m, t) -> { |
675 K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key"); |
782 K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key"); |
676 D oldContainer = m.computeIfAbsent(key, k -> downstreamSupplier.get()); |
783 A container = m.computeIfAbsent(key, k -> downstreamSupplier.get()); |
677 D newContainer = downstreamAccumulator.apply(oldContainer, t); |
784 downstreamAccumulator.accept(container, t); |
678 if (newContainer != oldContainer) |
|
679 m.put(key, newContainer); |
|
680 return m; |
|
681 }; |
785 }; |
682 return new CollectorImpl<>(mapFactory, accumulator, mapMerger(downstream.combiner()), CH_STRICT); |
786 BinaryOperator<Map<K, A>> merger = Collectors.<K, A, Map<K, A>>mapMerger(downstream.combiner()); |
683 } |
787 @SuppressWarnings("unchecked") |
684 |
788 Supplier<Map<K, A>> mangledFactory = (Supplier<Map<K, A>>) mapFactory; |
685 /** |
789 |
686 * Returns a {@code Collector} implementing a concurrent "group by" |
790 if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) { |
|
791 return new CollectorImpl<>(mangledFactory, accumulator, merger, CH_ID); |
|
792 } |
|
793 else { |
|
794 @SuppressWarnings("unchecked") |
|
795 Function<A, A> downstreamFinisher = (Function<A, A>) downstream.finisher(); |
|
796 Function<Map<K, A>, M> finisher = intermediate -> { |
|
797 intermediate.replaceAll((k, v) -> downstreamFinisher.apply(v)); |
|
798 @SuppressWarnings("unchecked") |
|
799 M castResult = (M) intermediate; |
|
800 return castResult; |
|
801 }; |
|
802 return new CollectorImpl<>(mangledFactory, accumulator, merger, finisher, CH_NOID); |
|
803 } |
|
804 } |
|
805 |
|
806 /** |
|
807 * Returns a concurrent {@code Collector} implementing a "group by" |
687 * operation on input elements of type {@code T}, grouping elements |
808 * operation on input elements of type {@code T}, grouping elements |
688 * according to a classification function. |
809 * according to a classification function. |
689 * |
810 * |
690 * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and |
811 * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and |
691 * {@link Collector.Characteristics#UNORDERED unordered} Collector. |
812 * {@link Collector.Characteristics#UNORDERED unordered} Collector. |
797 * |
921 * |
798 * @see #groupingByConcurrent(Function) |
922 * @see #groupingByConcurrent(Function) |
799 * @see #groupingByConcurrent(Function, Collector) |
923 * @see #groupingByConcurrent(Function, Collector) |
800 * @see #groupingBy(Function, Supplier, Collector) |
924 * @see #groupingBy(Function, Supplier, Collector) |
801 */ |
925 */ |
802 public static <T, K, D, M extends ConcurrentMap<K, D>> |
926 public static <T, K, A, D, M extends ConcurrentMap<K, D>> |
803 Collector<T, M> groupingByConcurrent(Function<? super T, ? extends K> classifier, |
927 Collector<T, ?, M> groupingByConcurrent(Function<? super T, ? extends K> classifier, |
804 Supplier<M> mapFactory, |
928 Supplier<M> mapFactory, |
805 Collector<? super T, D> downstream) { |
929 Collector<? super T, A, D> downstream) { |
806 Supplier<D> downstreamSupplier = downstream.resultSupplier(); |
930 Supplier<A> downstreamSupplier = downstream.supplier(); |
807 BiFunction<D, ? super T, D> downstreamAccumulator = downstream.accumulator(); |
931 BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator(); |
808 BinaryOperator<M> combiner = mapMerger(downstream.combiner()); |
932 BinaryOperator<ConcurrentMap<K, A>> merger = Collectors.<K, A, ConcurrentMap<K, A>>mapMerger(downstream.combiner()); |
|
933 @SuppressWarnings("unchecked") |
|
934 Supplier<ConcurrentMap<K, A>> mangledFactory = (Supplier<ConcurrentMap<K, A>>) mapFactory; |
|
935 BiConsumer<ConcurrentMap<K, A>, T> accumulator; |
809 if (downstream.characteristics().contains(Collector.Characteristics.CONCURRENT)) { |
936 if (downstream.characteristics().contains(Collector.Characteristics.CONCURRENT)) { |
810 BiFunction<M, T, M> accumulator = (m, t) -> { |
937 accumulator = (m, t) -> { |
811 K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key"); |
938 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); |
939 A resultContainer = m.computeIfAbsent(key, k -> downstreamSupplier.get()); |
813 return m; |
940 downstreamAccumulator.accept(resultContainer, t); |
814 }; |
941 }; |
815 return new CollectorImpl<>(mapFactory, accumulator, combiner, CH_CONCURRENT); |
942 } |
816 } else if (downstream.characteristics().contains(Collector.Characteristics.STRICTLY_MUTATIVE)) { |
943 else { |
817 BiFunction<M, T, M> accumulator = (m, t) -> { |
944 accumulator = (m, t) -> { |
818 K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key"); |
945 K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key"); |
819 D resultContainer = m.computeIfAbsent(key, k -> downstreamSupplier.get()); |
946 A resultContainer = m.computeIfAbsent(key, k -> downstreamSupplier.get()); |
820 synchronized (resultContainer) { |
947 synchronized (resultContainer) { |
821 downstreamAccumulator.apply(resultContainer, t); |
948 downstreamAccumulator.accept(resultContainer, t); |
822 } |
949 } |
823 return m; |
|
824 }; |
950 }; |
825 return new CollectorImpl<>(mapFactory, accumulator, combiner, CH_CONCURRENT); |
951 } |
826 } else { |
952 |
827 BiFunction<M, T, M> accumulator = (m, t) -> { |
953 if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) { |
828 K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key"); |
954 return new CollectorImpl<>(mangledFactory, accumulator, merger, CH_CONCURRENT_ID); |
829 do { |
955 } |
830 D oldResult = m.computeIfAbsent(key, k -> downstreamSupplier.get()); |
956 else { |
831 if (oldResult == null) { |
957 @SuppressWarnings("unchecked") |
832 if (m.putIfAbsent(key, downstreamAccumulator.apply(null, t)) == null) |
958 Function<A, A> downstreamFinisher = (Function<A, A>) downstream.finisher(); |
833 return m; |
959 Function<ConcurrentMap<K, A>, M> finisher = intermediate -> { |
834 } else { |
960 intermediate.replaceAll((k, v) -> downstreamFinisher.apply(v)); |
835 synchronized (oldResult) { |
961 @SuppressWarnings("unchecked") |
836 if (m.get(key) != oldResult) |
962 M castResult = (M) intermediate; |
837 continue; |
963 return castResult; |
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 }; |
964 }; |
846 return new CollectorImpl<>(mapFactory, accumulator, combiner, CH_CONCURRENT); |
965 return new CollectorImpl<>(mangledFactory, accumulator, merger, finisher, CH_CONCURRENT_NOID); |
847 } |
966 } |
848 } |
967 } |
849 |
968 |
850 /** |
969 /** |
851 * Returns a {@code Collector} which partitions the input elements according |
970 * Returns a {@code Collector} which partitions the input elements according |
875 * |
994 * |
876 * <p>There are no guarantees on the type, mutability, |
995 * <p>There are no guarantees on the type, mutability, |
877 * serializability, or thread-safety of the {@code Map} returned. |
996 * serializability, or thread-safety of the {@code Map} returned. |
878 * |
997 * |
879 * @param <T> the type of the input elements |
998 * @param <T> the type of the input elements |
|
999 * @param <A> the intermediate accumulation type of the downstream collector |
880 * @param <D> the result type of the downstream reduction |
1000 * @param <D> the result type of the downstream reduction |
881 * @param predicate a predicate used for classifying input elements |
1001 * @param predicate a predicate used for classifying input elements |
882 * @param downstream a {@code Collector} implementing the downstream |
1002 * @param downstream a {@code Collector} implementing the downstream |
883 * reduction |
1003 * reduction |
884 * @return a {@code Collector} implementing the cascaded partitioning |
1004 * @return a {@code Collector} implementing the cascaded partitioning |
885 * operation |
1005 * operation |
886 * |
1006 * |
887 * @see #partitioningBy(Predicate) |
1007 * @see #partitioningBy(Predicate) |
888 */ |
1008 */ |
889 public static <T, D> |
1009 public static <T, D, A> |
890 Collector<T, Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate, |
1010 Collector<T, ?, Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate, |
891 Collector<? super T, D> downstream) { |
1011 Collector<? super T, A, D> downstream) { |
892 BiFunction<D, ? super T, D> downstreamAccumulator = downstream.accumulator(); |
1012 @SuppressWarnings("unchecked") |
893 BiFunction<Map<Boolean, D>, T, Map<Boolean, D>> accumulator = (result, t) -> { |
1013 BiConsumer<D, ? super T> downstreamAccumulator = (BiConsumer<D, ? super T>) downstream.accumulator(); |
|
1014 BiConsumer<Map<Boolean, A>, T> accumulator = (result, t) -> { |
894 Partition<D> asPartition = ((Partition<D>) result); |
1015 Partition<D> asPartition = ((Partition<D>) result); |
895 if (predicate.test(t)) { |
1016 downstreamAccumulator.accept(predicate.test(t) ? asPartition.forTrue : asPartition.forFalse, 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 }; |
1017 }; |
906 return new CollectorImpl<>(() -> new Partition<>(downstream.resultSupplier().get(), |
1018 BinaryOperator<A> op = downstream.combiner(); |
907 downstream.resultSupplier().get()), |
1019 BinaryOperator<Map<Boolean, A>> merger = (m1, m2) -> { |
908 accumulator, partitionMerger(downstream.combiner()), CH_STRICT); |
1020 Partition<A> left = (Partition<A>) m1; |
909 } |
1021 Partition<A> right = (Partition<A>) m2; |
910 |
1022 return new Partition<>(op.apply(left.forTrue, right.forTrue), |
911 /** |
1023 op.apply(left.forFalse, right.forFalse)); |
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 }; |
1024 }; |
929 } |
1025 Supplier<Map<Boolean, A>> supplier = () -> new Partition<>(downstream.supplier().get(), |
930 |
1026 downstream.supplier().get()); |
931 /** |
1027 if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) { |
932 * Accumulate elements into a {@code Map} whose keys and values are the |
1028 return new CollectorImpl<>(supplier, accumulator, merger, CH_ID); |
933 * result of applying mapping functions to the input elements. |
1029 } |
934 * If the mapped keys contains duplicates (according to |
1030 else { |
|
1031 Function<Map<Boolean, A>, Map<Boolean, D>> finisher = (Map<Boolean, A> par) -> { |
|
1032 Partition<A> asAPartition = (Partition<A>) par; |
|
1033 return new Partition<>(downstream.finisher().apply(asAPartition.forTrue), |
|
1034 downstream.finisher().apply(asAPartition.forFalse)); |
|
1035 }; |
|
1036 return new CollectorImpl<>(supplier, accumulator, merger, finisher, CH_NOID); |
|
1037 } |
|
1038 } |
|
1039 |
|
1040 /** |
|
1041 * Returns a {@code Collector} that accumulate elements into a |
|
1042 * {@code Map} whose keys and values are the result of applying the provided |
|
1043 * mapping functions to the input elements. |
|
1044 * |
|
1045 * <p>If the mapped keys contains duplicates (according to |
935 * {@link Object#equals(Object)}), an {@code IllegalStateException} is |
1046 * {@link Object#equals(Object)}), an {@code IllegalStateException} is |
936 * thrown when the collection operation is performed. If the mapped keys |
1047 * thrown when the collection operation is performed. If the mapped keys |
937 * may have duplicates, use {@link #toMap(Function, Function, BinaryOperator)} |
1048 * may have duplicates, use {@link #toMap(Function, Function, BinaryOperator)} |
938 * instead. |
1049 * instead. |
939 * |
1050 * |
968 * @see #toMap(Function, Function, BinaryOperator) |
1079 * @see #toMap(Function, Function, BinaryOperator) |
969 * @see #toMap(Function, Function, BinaryOperator, Supplier) |
1080 * @see #toMap(Function, Function, BinaryOperator, Supplier) |
970 * @see #toConcurrentMap(Function, Function) |
1081 * @see #toConcurrentMap(Function, Function) |
971 */ |
1082 */ |
972 public static <T, K, U> |
1083 public static <T, K, U> |
973 Collector<T, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper, |
1084 Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper, |
974 Function<? super T, ? extends U> valueMapper) { |
1085 Function<? super T, ? extends U> valueMapper) { |
975 return toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new); |
1086 return toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new); |
976 } |
1087 } |
977 |
1088 |
978 /** |
1089 /** |
979 * Accumulate elements into a {@code Map} whose keys and values are the |
1090 * Returns a {@code Collector} that accumulate elements into a |
980 * result of applying mapping functions to the input elements. If the mapped |
1091 * {@code Map} whose keys and values are the result of applying the provided |
|
1092 * mapping functions to the input elements. |
|
1093 * |
|
1094 * <p>If the mapped |
981 * keys contains duplicates (according to {@link Object#equals(Object)}), |
1095 * keys contains duplicates (according to {@link Object#equals(Object)}), |
982 * the value mapping function is applied to each equal element, and the |
1096 * the value mapping function is applied to each equal element, and the |
983 * results are merged using the provided merging function. |
1097 * results are merged using the provided merging function. |
984 * |
1098 * |
985 * @apiNote |
1099 * @apiNote |
986 * There are multiple ways to deal with collisions between multiple elements |
1100 * There are multiple ways to deal with collisions between multiple elements |
987 * mapping to the same key. There are some predefined merging functions, |
1101 * mapping to the same key. The other forms of {@code toMap} simply use |
988 * such as {@link #throwingMerger()}, {@link #firstWinsMerger()}, and |
1102 * a merge function that throws unconditionally, but you can easily write |
989 * {@link #lastWinsMerger()}, that implement common policies, or you can |
1103 * more flexible merge policies. For example, if you have a stream |
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 |
1104 * 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 |
1105 * 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 |
1106 * do as follows to gracefully deals with these collisions, and produce a |
994 * {@code Map} mapping names to a concatenated list of addresses: |
1107 * {@code Map} mapping names to a concatenated list of addresses: |
995 * <pre>{@code |
1108 * <pre>{@code |
1052 * @see #toMap(Function, Function) |
1168 * @see #toMap(Function, Function) |
1053 * @see #toMap(Function, Function, BinaryOperator) |
1169 * @see #toMap(Function, Function, BinaryOperator) |
1054 * @see #toConcurrentMap(Function, Function, BinaryOperator, Supplier) |
1170 * @see #toConcurrentMap(Function, Function, BinaryOperator, Supplier) |
1055 */ |
1171 */ |
1056 public static <T, K, U, M extends Map<K, U>> |
1172 public static <T, K, U, M extends Map<K, U>> |
1057 Collector<T, M> toMap(Function<? super T, ? extends K> keyMapper, |
1173 Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper, |
1058 Function<? super T, ? extends U> valueMapper, |
1174 Function<? super T, ? extends U> valueMapper, |
1059 BinaryOperator<U> mergeFunction, |
1175 BinaryOperator<U> mergeFunction, |
1060 Supplier<M> mapSupplier) { |
1176 Supplier<M> mapSupplier) { |
1061 BiFunction<M, T, M> accumulator |
1177 BiConsumer<M, T> accumulator |
1062 = (map, element) -> { |
1178 = (map, element) -> map.merge(keyMapper.apply(element), |
1063 map.merge(keyMapper.apply(element), valueMapper.apply(element), mergeFunction); |
1179 valueMapper.apply(element), mergeFunction); |
1064 return map; |
1180 return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_ID); |
1065 }; |
1181 } |
1066 return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_STRICT); |
1182 |
1067 } |
1183 /** |
1068 |
1184 * Returns a {@code Collector} that accumulate elements into a |
1069 /** |
1185 * {@code ConcurrentMap} whose keys and values are the result of applying |
1070 * Accumulate elements into a {@code ConcurrentMap} whose keys and values |
1186 * the provided mapping functions to the input elements. |
1071 * are the result of applying mapping functions to the input elements. |
1187 * |
1072 * If the mapped keys contains duplicates (according to |
1188 * <p>If the mapped keys contains duplicates (according to |
1073 * {@link Object#equals(Object)}), an {@code IllegalStateException} is |
1189 * {@link Object#equals(Object)}), an {@code IllegalStateException} is |
1074 * thrown when the collection operation is performed. If the mapped keys |
1190 * thrown when the collection operation is performed. If the mapped keys |
1075 * may have duplicates, use |
1191 * may have duplicates, use |
1076 * {@link #toConcurrentMap(Function, Function, BinaryOperator)} instead. |
1192 * {@link #toConcurrentMap(Function, Function, BinaryOperator)} instead. |
1077 * |
1193 * |
1110 * @see #toMap(Function, Function) |
1226 * @see #toMap(Function, Function) |
1111 * @see #toConcurrentMap(Function, Function, BinaryOperator) |
1227 * @see #toConcurrentMap(Function, Function, BinaryOperator) |
1112 * @see #toConcurrentMap(Function, Function, BinaryOperator, Supplier) |
1228 * @see #toConcurrentMap(Function, Function, BinaryOperator, Supplier) |
1113 */ |
1229 */ |
1114 public static <T, K, U> |
1230 public static <T, K, U> |
1115 Collector<T, ConcurrentMap<K,U>> toConcurrentMap(Function<? super T, ? extends K> keyMapper, |
1231 Collector<T, ?, ConcurrentMap<K,U>> toConcurrentMap(Function<? super T, ? extends K> keyMapper, |
1116 Function<? super T, ? extends U> valueMapper) { |
1232 Function<? super T, ? extends U> valueMapper) { |
1117 return toConcurrentMap(keyMapper, valueMapper, throwingMerger(), ConcurrentHashMap::new); |
1233 return toConcurrentMap(keyMapper, valueMapper, throwingMerger(), ConcurrentHashMap::new); |
1118 } |
1234 } |
1119 |
1235 |
1120 /** |
1236 /** |
1121 * Accumulate elements into a {@code ConcurrentMap} whose keys and values |
1237 * Returns a {@code Collector} that accumulate elements into a |
1122 * are the result of applying mapping functions to the input elements. If |
1238 * {@code ConcurrentMap} whose keys and values are the result of applying |
1123 * the mapped keys contains duplicates (according to {@link Object#equals(Object)}), |
1239 * the provided mapping functions to the input elements. |
|
1240 * |
|
1241 * <p>If the mapped keys contains duplicates (according to {@link Object#equals(Object)}), |
1124 * the value mapping function is applied to each equal element, and the |
1242 * the value mapping function is applied to each equal element, and the |
1125 * results are merged using the provided merging function. |
1243 * results are merged using the provided merging function. |
1126 * |
1244 * |
1127 * @apiNote |
1245 * @apiNote |
1128 * There are multiple ways to deal with collisions between multiple elements |
1246 * There are multiple ways to deal with collisions between multiple elements |
1129 * mapping to the same key. There are some predefined merging functions, |
1247 * mapping to the same key. The other forms of {@code toConcurrentMap} simply use |
1130 * such as {@link #throwingMerger()}, {@link #firstWinsMerger()}, and |
1248 * a merge function that throws unconditionally, but you can easily write |
1131 * {@link #lastWinsMerger()}, that implement common policies, or you can |
1249 * more flexible merge policies. For example, if you have a stream |
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 |
1250 * 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 |
1251 * 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 |
1252 * do as follows to gracefully deals with these collisions, and produce a |
1136 * {@code Map} mapping names to a concatenated list of addresses: |
1253 * {@code Map} mapping names to a concatenated list of addresses: |
1137 * <pre>{@code |
1254 * <pre>{@code |