1 /*-
2 * #%L
3 * io.earcam.unexceptional
4 * %%
5 * Copyright (C) 2016 - 2017 earcam
6 * %%
7 * SPDX-License-Identifier: (BSD-3-Clause OR EPL-1.0 OR Apache-2.0 OR MIT)
8 *
9 * You <b>must</b> choose to accept, in full - any individual or combination of
10 * the following licenses:
11 * <ul>
12 * <li><a href="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</a></li>
13 * <li><a href="https://www.eclipse.org/legal/epl-v10.html">EPL-1.0</a></li>
14 * <li><a href="https://www.apache.org/licenses/LICENSE-2.0">Apache-2.0</a></li>
15 * <li><a href="https://opensource.org/licenses/MIT">MIT</a></li>
16 * </ul>
17 * #L%
18 */
19 package io.earcam.unexceptional;
20
21 import static io.earcam.unexceptional.Exceptional.*;
22
23 import java.io.Serializable; //NOSONAR SonarQube false positive - putting @SuppressWarnings("squid:UselessImportCheck") on class has no effect, can't put at package level either
24 import java.util.Iterator;
25 import java.util.Optional;
26 import java.util.Spliterator;
27 import java.util.stream.Collector;
28 import java.util.stream.DoubleStream;
29 import java.util.stream.IntStream;
30 import java.util.stream.LongStream;
31 import java.util.stream.Stream;
32
33 /**
34 * <p>
35 * {@link EmeticStream} provides a functional parallel to {@link Stream}, with methods taking checked equivalents of
36 * {@link java.util.function}
37 * </p>
38 *
39 * <h1>emetic</h1>
40 * <b>/ɪˈmɛtɪk/ </b>
41 * <p>
42 * <i>adjective:</i>
43 * </p>
44 * <p>
45 * 1. (of a substance) causing vomiting.
46 * </p>
47 *
48 * @param <T> the element type of this stream
49 *
50 * @since 0.2.0
51 */
52 @FunctionalInterface
53 public interface EmeticStream<T> extends AutoCloseable {
54
55 /**
56 * @return the wrapped stream
57 */
58 public abstract Stream<T> mapToStream();
59
60
61 /**
62 * @param function the checked function which, when applied to the {@code value} produces the {@link Stream}
63 * to be returned
64 * @param value argument for the function
65 * @return the {@link Stream} result of applying {@code function} to {@code value}
66 *
67 * @param <T> the function's argument type
68 * @param <R> the element type of this stream
69 *
70 * @since 0.2.0
71 */
72 public static <T, R> EmeticStream<R> emesis(CheckedFunction<T, Stream<R>, ?> function, T value)
73 {
74 return emesis(apply(function, value));
75 }
76
77
78 /**
79 * Wrap a stream in order to invoke check functions on it
80 *
81 * @param stream the underlying {@link Stream}
82 * @return an {@link EmeticStream}
83 *
84 * @param <T> the {@code stream}'s element type
85 *
86 * @since 0.2.0
87 */
88 @SuppressWarnings("squid:S1905") // SonarQube false positive
89 public static <T> EmeticStream<T> emesis(Stream<T> stream)
90 {
91 return (EmeticStream<T> & Serializable) () -> stream;
92 }
93
94
95 /**
96 * @return a parallel emetic stream
97 *
98 * @see Stream#parallel()
99 *
100 * @since 0.2.0
101 */
102 public default EmeticStream<T> parallel()
103 {
104 return mapToStream().isParallel() ? this : emesis(mapToStream().parallel());
105 }
106
107
108 /**
109 * @return a sequential emetic stream
110 *
111 * @see Stream#sequential()
112 *
113 * @since 0.2.0
114 */
115 public default EmeticStream<T> sequential()
116 {
117 return !mapToStream().isParallel() ? this : emesis(mapToStream().sequential());
118 }
119
120
121 /**
122 * Returns an equivalent stream that is unordered.
123 *
124 * @return an unordered emetic stream
125 *
126 * @see java.util.stream.BaseStream#unordered()
127 *
128 * @since 0.5.0
129 */
130 public default EmeticStream<T> unordered()
131 {
132 return emesis(mapToStream().unordered());
133 }
134
135
136 /**
137 * Returns an iterator for the elements of the wrapped stream.
138 *
139 * @return the element iterator for the wrapped stream
140 *
141 * @see java.util.stream.BaseStream#iterator()
142 *
143 * @since 0.5.0
144 */
145 public default Iterator<T> iterator()
146 {
147 return mapToStream().iterator();
148 }
149
150
151 /**
152 * Returns a spliterator for the elements of the wrapped stream.
153 *
154 * @return the element spliterator for this stream
155 *
156 * @see java.util.stream.BaseStream#spliterator()
157 *
158 * @since 0.5.0
159 */
160 public default Spliterator<T> spliterator()
161 {
162 return mapToStream().spliterator();
163 }
164
165
166 /**
167 * Returns whether the wrapped stream would execute in parallel, if a terminal operation were executed.
168 *
169 * @return {@code true} if the wrapped stream would execute in parallel
170 *
171 * @see java.util.stream.BaseStream#isParallel()
172 *
173 * @since 0.5.0
174 */
175 public default boolean isParallel()
176 {
177 return mapToStream().isParallel();
178 }
179
180
181 /**
182 * @param predicate a non-interfering and stateless, checked predicate 𝗣 to apply
183 * to all elements in the stream 𝕊
184 * @return ∀ e ∈ 𝕊: 𝗣(e)
185 *
186 * @see Stream#allMatch(java.util.function.Predicate)
187 *
188 * @since 0.2.0
189 */
190 public default boolean allMatch(CheckedPredicate<? super T, ?> predicate)
191 {
192 return mapToStream().allMatch(uncheckPredicate(predicate));
193 }
194
195
196 /**
197 * @param predicate a non-interfering and stateless, checked predicate 𝗣 to apply
198 * to all elements in the stream 𝕊
199 * @return ∃ e ∈ 𝕊: 𝗣(e)
200 *
201 * @see Stream#anyMatch(java.util.function.Predicate)
202 *
203 * @since 0.2.0
204 */
205 public default boolean anyMatch(CheckedPredicate<? super T, ?> predicate)
206 {
207 return mapToStream().anyMatch(uncheckPredicate(predicate));
208 }
209
210
211 /**
212 * @param collector {@link Collector} performing reduction and supplying result
213 * @return the result
214 *
215 * @param <A> mutable accumulator type
216 * @param <R> reduction result type
217 *
218 * @see Stream#collect(Collector)
219 *
220 * @since 0.2.0
221 */
222 public default <R, A> R collect(Collector<? super T, A, R> collector)
223 {
224 return mapToStream().collect(collector);
225 }
226
227
228 /**
229 * @param supplier creates a new (potentially partial) result container
230 * @param accumulator associative, non-interfering, stateless function, adding element to result
231 * @param combiner combines the accumulated results
232 * @return the collected result
233 *
234 * @param <R> result type
235 *
236 * @see Stream#collect(java.util.function.Supplier, java.util.function.BiConsumer, java.util.function.BiConsumer)
237 *
238 * @since 0.2.0
239 */
240 public default <R> R collect(CheckedSupplier<R, ?> supplier, CheckedBiConsumer<R, ? super T, ?> accumulator, CheckedBiConsumer<R, R, ?> combiner)
241 {
242 return mapToStream().collect(uncheckSupplier(supplier), uncheckBiConsumer(accumulator), uncheckBiConsumer(combiner));
243 }
244
245
246 /**
247 * @param predicate a non-interfering, stateless predicate determining which elements travel down{@code Stream}
248 * @return the new {@link EmeticStream}
249 *
250 * @see Stream#filter(java.util.function.Predicate)
251 *
252 * @since 0.2.0
253 */
254 public default EmeticStream<T> filter(CheckedPredicate<? super T, ?> predicate)
255 {
256 return emesis(mapToStream().filter(uncheckPredicate(predicate)));
257 }
258
259
260 /**
261 * @param <R> element type of the new stream
262 *
263 * @param mapper a non-interfering, stateless function transforming {@code <T>} to {@code Stream<R>}
264 * @return the new {@link EmeticStream}
265 *
266 * @see Stream#flatMap(java.util.function.Function)
267 *
268 * @since 0.2.0
269 */
270 public default <R> EmeticStream<R> flatMap(CheckedFunction<? super T, ? extends Stream<? extends R>, ?> mapper)
271 {
272 return emesis(mapToStream().flatMap(uncheckFunction(mapper)));
273 }
274
275
276 /**
277 * @param mapper a non-interfering, stateless function transforming {@code <T>} to {@code DoubleStream}
278 * @return the new {@link DoubleStream}
279 *
280 * @see Stream#flatMapToDouble(java.util.function.Function)
281 *
282 * @since 0.2.0
283 */
284 public default DoubleStream flatMapToDouble(CheckedFunction<? super T, ? extends DoubleStream, ?> mapper)
285 {
286 return mapToStream().flatMapToDouble(uncheckFunction(mapper));
287 }
288
289
290 /**
291 * @param mapper a non-interfering, stateless function transforming {@code <T>} to {@code IntStream}
292 * @return the new {@link IntStream}
293 *
294 * @see Stream#flatMapToInt(java.util.function.Function)
295 *
296 * @since 0.2.0
297 */
298 public default IntStream flatMapToInt(CheckedFunction<? super T, ? extends IntStream, ?> mapper)
299 {
300 return mapToStream().flatMapToInt(uncheckFunction(mapper));
301 }
302
303
304 /**
305 * @param mapper a non-interfering, stateless function transforming {@code <T>} to {@code LongStream}
306 * @return the new {@link EmeticStream}
307 *
308 * @see Stream#flatMapToLong(java.util.function.Function)
309 *
310 * @since 0.2.0
311 */
312 public default LongStream flatMapToLong(CheckedFunction<? super T, ? extends LongStream, ?> mapper)
313 {
314 return mapToStream().flatMapToLong(uncheckFunction(mapper));
315 }
316
317
318 /**
319 * @param action a non-interfering action to apply to each element
320 * @see Stream#forEach(java.util.function.Consumer)
321 *
322 * @since 0.2.0
323 */
324 public default void forEach(CheckedConsumer<? super T, ?> action)
325 {
326 mapToStream().forEach(uncheckConsumer(action));
327 }
328
329
330 /**
331 * @param action a non-interfering action to apply to each element
332 * @see Stream#forEachOrdered(java.util.function.Consumer)
333 *
334 * @since 0.2.0
335 */
336 public default void forEachOrdered(CheckedConsumer<? super T, ?> action)
337 {
338 mapToStream().forEachOrdered(uncheckConsumer(action));
339 }
340
341
342 /**
343 * @param <R> the element type of returned {@link Stream}
344 *
345 * @param mapper a non-interfering, stateless function transforming {@code <T>} to {@code <R>}
346 * @return the new {@link EmeticStream}
347 *
348 * @see Stream#map(java.util.function.Function)
349 *
350 * @since 0.2.0
351 */
352 public default <R> EmeticStream<R> map(CheckedFunction<? super T, ? extends R, ?> mapper)
353 {
354 return emesis(mapToStream().map(uncheckFunction(mapper)));
355 }
356
357
358 /**
359 * @param mapper a non-interfering, stateless function transforming {@code <T>} to {@code double}
360 * @return the new {@link EmeticStream}
361 *
362 * @see Stream#mapToDouble(java.util.function.ToDoubleFunction)
363 *
364 * @since 0.2.0
365 */
366 public default DoubleStream mapToDouble(CheckedToDoubleFunction<? super T, ?> mapper)
367 {
368 return mapToStream().mapToDouble(uncheckToDoubleFunction(mapper));
369 }
370
371
372 /**
373 * @param mapper a non-interfering, stateless function transforming {@code <T>} to {@code int}
374 * @return the new {@link EmeticStream}
375 *
376 * @see Stream#mapToInt(java.util.function.ToIntFunction)
377 *
378 * @since 0.2.0
379 */
380 public default IntStream mapToInt(CheckedToIntFunction<? super T, ?> mapper)
381 {
382 return mapToStream().mapToInt(uncheckToIntFunction(mapper));
383 }
384
385
386 /**
387 * @param mapper a non-interfering, stateless function transforming {@code <T>} to {@code long}
388 * @return the new {@link EmeticStream}
389 *
390 * @see Stream#mapToLong(java.util.function.ToLongFunction)
391 *
392 * @since 0.2.0
393 */
394 public default LongStream mapToLong(CheckedToLongFunction<? super T, ?> mapper)
395 {
396 return mapToStream().mapToLong(uncheckToLongFunction(mapper));
397 }
398
399
400 /**
401 * @param comparator a non-interfering, stateless comparator
402 * @return an {@link Optional} as per {@link Stream#max(java.util.Comparator)}
403 *
404 * @see Stream#max(java.util.Comparator)
405 *
406 * @since 0.2.0
407 */
408 public default Optional<T> max(CheckedComparator<? super T, ?> comparator)
409 {
410 return mapToStream().max(uncheckComparator(comparator));
411 }
412
413
414 /**
415 * @param comparator a non-interfering, stateless comparator
416 * @return an {@link Optional} as per {@link Stream#max(java.util.Comparator)}
417 *
418 * @see Stream#min(java.util.Comparator)
419 *
420 * @since 0.2.0
421 */
422 public default Optional<T> min(CheckedComparator<? super T, ?> comparator)
423 {
424 return mapToStream().min(uncheckComparator(comparator));
425 }
426
427
428 /**
429 * @param predicate a non-interfering, stateless, checked predicate 𝗣 to apply
430 * to all elements in the stream 𝕊
431 *
432 * @return ∄ e ∈ 𝕊: 𝗣(e)
433 *
434 * @see Stream#noneMatch(java.util.function.Predicate)
435 *
436 * @since 0.2.0
437 */
438 public default boolean noneMatch(CheckedPredicate<? super T, ?> predicate)
439 {
440 return mapToStream().noneMatch(uncheckPredicate(predicate));
441 }
442
443
444 /**
445 * @param action non-interfering action applied to elements of the underlying Stream
446 * @return the new EmeticStream
447 *
448 * @see Stream#peek(java.util.function.Consumer)
449 *
450 * @since 0.2.0
451 */
452 public default EmeticStream<T> peek(CheckedConsumer<? super T, ?> action)
453 {
454 return emesis(mapToStream().peek(uncheckConsumer(action)));
455 }
456
457
458 /**
459 *
460 * @param accumulator an associative, non-interfering and stateless function
461 * @return the reduction
462 *
463 * @see Stream#reduce(java.util.function.BinaryOperator)
464 *
465 * @since 0.2.0
466 */
467 public default Optional<T> reduce(CheckedBinaryOperator<T, ?> accumulator)
468 {
469 return mapToStream().reduce(uncheckBinaryOperator(accumulator));
470 }
471
472
473 /**
474 *
475 * @param identity seed value for accumulator
476 * @param accumulator an associative, non-interfering and stateless function
477 * @return the reduction
478 *
479 * @see Stream#reduce(Object, java.util.function.BinaryOperator)
480 *
481 * @since 0.2.0
482 */
483 public default T reduce(T identity, CheckedBinaryOperator<T, ?> accumulator)
484 {
485 return mapToStream().reduce(identity, uncheckBinaryOperator(accumulator));
486 }
487
488
489 /**
490 *
491 * @param comparator non-interfering, stateless comparator to sort
492 * @return an emetic stream wrapping the underlying sorted stream
493 *
494 * @see Stream#sorted(java.util.Comparator)
495 *
496 * @since 0.2.0
497 */
498 public default EmeticStream<T> sorted(CheckedComparator<? super T, ?> comparator)
499 {
500 return emesis(mapToStream().sorted(Exceptional.uncheckComparator(comparator)));
501 }
502
503
504 /**
505 * @return count of elements in this stream
506 *
507 * @see Stream#count()
508 *
509 * @since 0.2.0
510 */
511 public default long count()
512 {
513 return mapToStream().count();
514 }
515
516
517 /**
518 * Returns an equivalent stream with the additional close handler.
519 *
520 * @param closeHandler A runnable executed when the stream is closed
521 * @return a stream with a handler registered
522 *
523 * @see java.util.stream.BaseStream#onClose(Runnable)
524 *
525 * @since 0.5.0
526 */
527 public default EmeticStream<T> onClose(Runnable closeHandler)
528 {
529 return emesis(mapToStream().onClose(closeHandler));
530 }
531
532
533 /**
534 * Closes the wrapped stream, invoking all registered close handlers.
535 *
536 * @see AutoCloseable#close()
537 * @see java.util.stream.BaseStream#unordered()
538 *
539 * @since 0.5.0
540 */
541 @Override
542 public default void close()
543 {
544 mapToStream().close();
545 }
546 }