View Javadoc
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/&nbsp;</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 }