120 = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.UNORDERED,
121 Collector.Characteristics.IDENTITY_FINISH));
122 static final Set<Collector.Characteristics> CH_NOID = Collections.emptySet();
123
124 private Collectors() { }
125
126 /**
127 * Returns a merge function, suitable for use in
128 * {@link Map#merge(Object, Object, BiFunction) Map.merge()} or
129 * {@link #toMap(Function, Function, BinaryOperator) toMap()}, which always
130 * throws {@code IllegalStateException}. This can be used to enforce the
131 * assumption that the elements being collected are distinct.
132 *
133 * @param <T> the type of input arguments to the merge function
134 * @return a merge function which always throw {@code IllegalStateException}
135 */
136 private static <T> BinaryOperator<T> throwingMerger() {
137 return (u,v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); };
138 }
139
140 /**
141 * Simple implementation class for {@code Collector}.
142 *
143 * @param <T> the type of elements to be collected
144 * @param <R> the type of the result
145 */
146 static class CollectorImpl<T, A, R> implements Collector<T, A, R> {
147 private final Supplier<A> supplier;
148 private final BiConsumer<A, T> accumulator;
149 private final BinaryOperator<A> combiner;
150 private final Function<A, R> finisher;
151 private final Set<Characteristics> characteristics;
152
153 CollectorImpl(Supplier<A> supplier,
154 BiConsumer<A, T> accumulator,
155 BinaryOperator<A> combiner,
156 Function<A,R> finisher,
157 Set<Characteristics> characteristics) {
158 this.supplier = supplier;
159 this.accumulator = accumulator;
160 this.combiner = combiner;
161 this.finisher = finisher;
162 this.characteristics = characteristics;
163 }
164
165 CollectorImpl(Supplier<A> supplier,
166 BiConsumer<A, T> accumulator,
167 BinaryOperator<A> combiner,
168 Set<Characteristics> characteristics) {
169 this(supplier, accumulator, combiner, i -> (R) i, characteristics);
170 }
171
172 @Override
173 public BiConsumer<A, T> accumulator() {
174 return accumulator;
175 }
176
177 @Override
178 public Supplier<A> supplier() {
179 return supplier;
180 }
181
182 @Override
183 public BinaryOperator<A> combiner() {
184 return combiner;
185 }
186
187 @Override
188 public Function<A, R> finisher() {
189 return finisher;
192 @Override
193 public Set<Characteristics> characteristics() {
194 return characteristics;
195 }
196 }
197
198 /**
199 * Returns a {@code Collector} that accumulates the input elements into a
200 * new {@code Collection}, in encounter order. The {@code Collection} is
201 * created by the provided factory.
202 *
203 * @param <T> the type of the input elements
204 * @param <C> the type of the resulting {@code Collection}
205 * @param collectionFactory a {@code Supplier} which returns a new, empty
206 * {@code Collection} of the appropriate type
207 * @return a {@code Collector} which collects all the input elements into a
208 * {@code Collection}, in encounter order
209 */
210 public static <T, C extends Collection<T>>
211 Collector<T, ?, C> toCollection(Supplier<C> collectionFactory) {
212 return new CollectorImpl<>(collectionFactory, Collection::add,
213 (r1, r2) -> { r1.addAll(r2); return r1; },
214 CH_ID);
215 }
216
217 /**
218 * Returns a {@code Collector} that accumulates the input elements into a
219 * new {@code List}. There are no guarantees on the type, mutability,
220 * serializability, or thread-safety of the {@code List} returned.
221 *
222 * @param <T> the type of the input elements
223 * @return a {@code Collector} which collects all the input elements into a
224 * {@code List}, in encounter order
225 */
226 public static <T>
227 Collector<T, ?, List<T>> toList() {
228 return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
229 (left, right) -> { left.addAll(right); return left; },
230 CH_ID);
231 }
232
1029 * {@code Map<Boolean, D>} whose values are the result of the downstream
1030 * reduction.
1031 *
1032 * <p>There are no guarantees on the type, mutability,
1033 * serializability, or thread-safety of the {@code Map} returned.
1034 *
1035 * @param <T> the type of the input elements
1036 * @param <A> the intermediate accumulation type of the downstream collector
1037 * @param <D> the result type of the downstream reduction
1038 * @param predicate a predicate used for classifying input elements
1039 * @param downstream a {@code Collector} implementing the downstream
1040 * reduction
1041 * @return a {@code Collector} implementing the cascaded partitioning
1042 * operation
1043 *
1044 * @see #partitioningBy(Predicate)
1045 */
1046 public static <T, D, A>
1047 Collector<T, ?, Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate,
1048 Collector<? super T, A, D> downstream) {
1049 @SuppressWarnings("unchecked")
1050 BiConsumer<D, ? super T> downstreamAccumulator = (BiConsumer<D, ? super T>) downstream.accumulator();
1051 BiConsumer<Map<Boolean, A>, T> accumulator = (result, t) -> {
1052 Partition<D> asPartition = ((Partition<D>) result);
1053 downstreamAccumulator.accept(predicate.test(t) ? asPartition.forTrue : asPartition.forFalse, t);
1054 };
1055 BinaryOperator<A> op = downstream.combiner();
1056 BinaryOperator<Map<Boolean, A>> merger = (m1, m2) -> {
1057 Partition<A> left = (Partition<A>) m1;
1058 Partition<A> right = (Partition<A>) m2;
1059 return new Partition<>(op.apply(left.forTrue, right.forTrue),
1060 op.apply(left.forFalse, right.forFalse));
1061 };
1062 Supplier<Map<Boolean, A>> supplier = () -> new Partition<>(downstream.supplier().get(),
1063 downstream.supplier().get());
1064 if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
1065 return new CollectorImpl<>(supplier, accumulator, merger, CH_ID);
1066 }
1067 else {
1068 Function<Map<Boolean, A>, Map<Boolean, D>> finisher = (Map<Boolean, A> par) -> {
1069 Partition<A> asAPartition = (Partition<A>) par;
1070 return new Partition<>(downstream.finisher().apply(asAPartition.forTrue),
1071 downstream.finisher().apply(asAPartition.forFalse));
1072 };
1073 return new CollectorImpl<>(supplier, accumulator, merger, finisher, CH_NOID);
1074 }
1075 }
1076
1077 /**
1078 * Returns a {@code Collector} that accumulate elements into a
1079 * {@code Map} whose keys and values are the result of applying the provided
1080 * mapping functions to the input elements.
1081 *
1082 * <p>If the mapped keys contains duplicates (according to
1083 * {@link Object#equals(Object)}), an {@code IllegalStateException} is
1084 * thrown when the collection operation is performed. If the mapped keys
1085 * may have duplicates, use {@link #toMap(Function, Function, BinaryOperator)}
1086 * instead.
1087 *
1088 * @apiNote
1089 * It is common for either the key or the value to be the input elements.
1090 * In this case, the utility method
1091 * {@link java.util.function.Function#identity()} may be helpful.
1092 * For example, the following produces a {@code Map} mapping
|
120 = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.UNORDERED,
121 Collector.Characteristics.IDENTITY_FINISH));
122 static final Set<Collector.Characteristics> CH_NOID = Collections.emptySet();
123
124 private Collectors() { }
125
126 /**
127 * Returns a merge function, suitable for use in
128 * {@link Map#merge(Object, Object, BiFunction) Map.merge()} or
129 * {@link #toMap(Function, Function, BinaryOperator) toMap()}, which always
130 * throws {@code IllegalStateException}. This can be used to enforce the
131 * assumption that the elements being collected are distinct.
132 *
133 * @param <T> the type of input arguments to the merge function
134 * @return a merge function which always throw {@code IllegalStateException}
135 */
136 private static <T> BinaryOperator<T> throwingMerger() {
137 return (u,v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); };
138 }
139
140 @SuppressWarnings("unchecked")
141 private static <I, R> Function<I, R> castingIdentity() {
142 return i -> (R) i;
143 }
144
145 /**
146 * Simple implementation class for {@code Collector}.
147 *
148 * @param <T> the type of elements to be collected
149 * @param <R> the type of the result
150 */
151 static class CollectorImpl<T, A, R> implements Collector<T, A, R> {
152 private final Supplier<A> supplier;
153 private final BiConsumer<A, T> accumulator;
154 private final BinaryOperator<A> combiner;
155 private final Function<A, R> finisher;
156 private final Set<Characteristics> characteristics;
157
158 CollectorImpl(Supplier<A> supplier,
159 BiConsumer<A, T> accumulator,
160 BinaryOperator<A> combiner,
161 Function<A,R> finisher,
162 Set<Characteristics> characteristics) {
163 this.supplier = supplier;
164 this.accumulator = accumulator;
165 this.combiner = combiner;
166 this.finisher = finisher;
167 this.characteristics = characteristics;
168 }
169
170 CollectorImpl(Supplier<A> supplier,
171 BiConsumer<A, T> accumulator,
172 BinaryOperator<A> combiner,
173 Set<Characteristics> characteristics) {
174 this(supplier, accumulator, combiner, castingIdentity(), characteristics);
175 }
176
177 @Override
178 public BiConsumer<A, T> accumulator() {
179 return accumulator;
180 }
181
182 @Override
183 public Supplier<A> supplier() {
184 return supplier;
185 }
186
187 @Override
188 public BinaryOperator<A> combiner() {
189 return combiner;
190 }
191
192 @Override
193 public Function<A, R> finisher() {
194 return finisher;
197 @Override
198 public Set<Characteristics> characteristics() {
199 return characteristics;
200 }
201 }
202
203 /**
204 * Returns a {@code Collector} that accumulates the input elements into a
205 * new {@code Collection}, in encounter order. The {@code Collection} is
206 * created by the provided factory.
207 *
208 * @param <T> the type of the input elements
209 * @param <C> the type of the resulting {@code Collection}
210 * @param collectionFactory a {@code Supplier} which returns a new, empty
211 * {@code Collection} of the appropriate type
212 * @return a {@code Collector} which collects all the input elements into a
213 * {@code Collection}, in encounter order
214 */
215 public static <T, C extends Collection<T>>
216 Collector<T, ?, C> toCollection(Supplier<C> collectionFactory) {
217 return new CollectorImpl<>(collectionFactory, Collection<T>::add,
218 (r1, r2) -> { r1.addAll(r2); return r1; },
219 CH_ID);
220 }
221
222 /**
223 * Returns a {@code Collector} that accumulates the input elements into a
224 * new {@code List}. There are no guarantees on the type, mutability,
225 * serializability, or thread-safety of the {@code List} returned.
226 *
227 * @param <T> the type of the input elements
228 * @return a {@code Collector} which collects all the input elements into a
229 * {@code List}, in encounter order
230 */
231 public static <T>
232 Collector<T, ?, List<T>> toList() {
233 return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
234 (left, right) -> { left.addAll(right); return left; },
235 CH_ID);
236 }
237
1034 * {@code Map<Boolean, D>} whose values are the result of the downstream
1035 * reduction.
1036 *
1037 * <p>There are no guarantees on the type, mutability,
1038 * serializability, or thread-safety of the {@code Map} returned.
1039 *
1040 * @param <T> the type of the input elements
1041 * @param <A> the intermediate accumulation type of the downstream collector
1042 * @param <D> the result type of the downstream reduction
1043 * @param predicate a predicate used for classifying input elements
1044 * @param downstream a {@code Collector} implementing the downstream
1045 * reduction
1046 * @return a {@code Collector} implementing the cascaded partitioning
1047 * operation
1048 *
1049 * @see #partitioningBy(Predicate)
1050 */
1051 public static <T, D, A>
1052 Collector<T, ?, Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate,
1053 Collector<? super T, A, D> downstream) {
1054 BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
1055 BiConsumer<Partition<A>, T> accumulator = (result, t) ->
1056 downstreamAccumulator.accept(predicate.test(t) ? result.forTrue : result.forFalse, t);
1057 BinaryOperator<A> op = downstream.combiner();
1058 BinaryOperator<Partition<A>> merger = (left, right) ->
1059 new Partition<>(op.apply(left.forTrue, right.forTrue),
1060 op.apply(left.forFalse, right.forFalse));
1061 Supplier<Partition<A>> supplier = () ->
1062 new Partition<>(downstream.supplier().get(),
1063 downstream.supplier().get());
1064 if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
1065 return new CollectorImpl<>(supplier, accumulator, merger, CH_ID);
1066 }
1067 else {
1068 Function<Partition<A>, Map<Boolean, D>> finisher = par ->
1069 new Partition<>(downstream.finisher().apply(par.forTrue),
1070 downstream.finisher().apply(par.forFalse));
1071 return new CollectorImpl<>(supplier, accumulator, merger, finisher, CH_NOID);
1072 }
1073 }
1074
1075 /**
1076 * Returns a {@code Collector} that accumulate elements into a
1077 * {@code Map} whose keys and values are the result of applying the provided
1078 * mapping functions to the input elements.
1079 *
1080 * <p>If the mapped keys contains duplicates (according to
1081 * {@link Object#equals(Object)}), an {@code IllegalStateException} is
1082 * thrown when the collection operation is performed. If the mapped keys
1083 * may have duplicates, use {@link #toMap(Function, Function, BinaryOperator)}
1084 * instead.
1085 *
1086 * @apiNote
1087 * It is common for either the key or the value to be the input elements.
1088 * In this case, the utility method
1089 * {@link java.util.function.Function#identity()} may be helpful.
1090 * For example, the following produces a {@code Map} mapping
|