EmeticStream.java
/*-
* #%L
* io.earcam.unexceptional
* %%
* Copyright (C) 2016 - 2017 earcam
* %%
* SPDX-License-Identifier: (BSD-3-Clause OR EPL-1.0 OR Apache-2.0 OR MIT)
*
* You <b>must</b> choose to accept, in full - any individual or combination of
* the following licenses:
* <ul>
* <li><a href="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</a></li>
* <li><a href="https://www.eclipse.org/legal/epl-v10.html">EPL-1.0</a></li>
* <li><a href="https://www.apache.org/licenses/LICENSE-2.0">Apache-2.0</a></li>
* <li><a href="https://opensource.org/licenses/MIT">MIT</a></li>
* </ul>
* #L%
*/
package io.earcam.unexceptional;
import static io.earcam.unexceptional.Exceptional.*;
import java.io.Serializable; //NOSONAR SonarQube false positive - putting @SuppressWarnings("squid:UselessImportCheck") on class has no effect, can't put at package level either
import java.util.Iterator;
import java.util.Optional;
import java.util.Spliterator;
import java.util.stream.Collector;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
import java.util.stream.Stream;
/**
* <p>
* {@link EmeticStream} provides a functional parallel to {@link Stream}, with methods taking checked equivalents of
* {@link java.util.function}
* </p>
*
* <h1>emetic</h1>
* <b>/ɪˈmɛtɪk/ </b>
* <p>
* <i>adjective:</i>
* </p>
* <p>
* 1. (of a substance) causing vomiting.
* </p>
*
* @param <T> the element type of this stream
*
* @since 0.2.0
*/
@FunctionalInterface
public interface EmeticStream<T> extends AutoCloseable {
/**
* @return the wrapped stream
*/
public abstract Stream<T> mapToStream();
/**
* @param function the checked function which, when applied to the {@code value} produces the {@link Stream}
* to be returned
* @param value argument for the function
* @return the {@link Stream} result of applying {@code function} to {@code value}
*
* @param <T> the function's argument type
* @param <R> the element type of this stream
*
* @since 0.2.0
*/
public static <T, R> EmeticStream<R> emesis(CheckedFunction<T, Stream<R>, ?> function, T value)
{
return emesis(apply(function, value));
}
/**
* Wrap a stream in order to invoke check functions on it
*
* @param stream the underlying {@link Stream}
* @return an {@link EmeticStream}
*
* @param <T> the {@code stream}'s element type
*
* @since 0.2.0
*/
@SuppressWarnings("squid:S1905") // SonarQube false positive
public static <T> EmeticStream<T> emesis(Stream<T> stream)
{
return (EmeticStream<T> & Serializable) () -> stream;
}
/**
* @return a parallel emetic stream
*
* @see Stream#parallel()
*
* @since 0.2.0
*/
public default EmeticStream<T> parallel()
{
return mapToStream().isParallel() ? this : emesis(mapToStream().parallel());
}
/**
* @return a sequential emetic stream
*
* @see Stream#sequential()
*
* @since 0.2.0
*/
public default EmeticStream<T> sequential()
{
return !mapToStream().isParallel() ? this : emesis(mapToStream().sequential());
}
/**
* Returns an equivalent stream that is unordered.
*
* @return an unordered emetic stream
*
* @see java.util.stream.BaseStream#unordered()
*
* @since 0.5.0
*/
public default EmeticStream<T> unordered()
{
return emesis(mapToStream().unordered());
}
/**
* Returns an iterator for the elements of the wrapped stream.
*
* @return the element iterator for the wrapped stream
*
* @see java.util.stream.BaseStream#iterator()
*
* @since 0.5.0
*/
public default Iterator<T> iterator()
{
return mapToStream().iterator();
}
/**
* Returns a spliterator for the elements of the wrapped stream.
*
* @return the element spliterator for this stream
*
* @see java.util.stream.BaseStream#spliterator()
*
* @since 0.5.0
*/
public default Spliterator<T> spliterator()
{
return mapToStream().spliterator();
}
/**
* Returns whether the wrapped stream would execute in parallel, if a terminal operation were executed.
*
* @return {@code true} if the wrapped stream would execute in parallel
*
* @see java.util.stream.BaseStream#isParallel()
*
* @since 0.5.0
*/
public default boolean isParallel()
{
return mapToStream().isParallel();
}
/**
* @param predicate a non-interfering and stateless, checked predicate 𝗣 to apply
* to all elements in the stream 𝕊
* @return ∀ e ∈ 𝕊: 𝗣(e)
*
* @see Stream#allMatch(java.util.function.Predicate)
*
* @since 0.2.0
*/
public default boolean allMatch(CheckedPredicate<? super T, ?> predicate)
{
return mapToStream().allMatch(uncheckPredicate(predicate));
}
/**
* @param predicate a non-interfering and stateless, checked predicate 𝗣 to apply
* to all elements in the stream 𝕊
* @return ∃ e ∈ 𝕊: 𝗣(e)
*
* @see Stream#anyMatch(java.util.function.Predicate)
*
* @since 0.2.0
*/
public default boolean anyMatch(CheckedPredicate<? super T, ?> predicate)
{
return mapToStream().anyMatch(uncheckPredicate(predicate));
}
/**
* @param collector {@link Collector} performing reduction and supplying result
* @return the result
*
* @param <A> mutable accumulator type
* @param <R> reduction result type
*
* @see Stream#collect(Collector)
*
* @since 0.2.0
*/
public default <R, A> R collect(Collector<? super T, A, R> collector)
{
return mapToStream().collect(collector);
}
/**
* @param supplier creates a new (potentially partial) result container
* @param accumulator associative, non-interfering, stateless function, adding element to result
* @param combiner combines the accumulated results
* @return the collected result
*
* @param <R> result type
*
* @see Stream#collect(java.util.function.Supplier, java.util.function.BiConsumer, java.util.function.BiConsumer)
*
* @since 0.2.0
*/
public default <R> R collect(CheckedSupplier<R, ?> supplier, CheckedBiConsumer<R, ? super T, ?> accumulator, CheckedBiConsumer<R, R, ?> combiner)
{
return mapToStream().collect(uncheckSupplier(supplier), uncheckBiConsumer(accumulator), uncheckBiConsumer(combiner));
}
/**
* @param predicate a non-interfering, stateless predicate determining which elements travel down{@code Stream}
* @return the new {@link EmeticStream}
*
* @see Stream#filter(java.util.function.Predicate)
*
* @since 0.2.0
*/
public default EmeticStream<T> filter(CheckedPredicate<? super T, ?> predicate)
{
return emesis(mapToStream().filter(uncheckPredicate(predicate)));
}
/**
* @param <R> element type of the new stream
*
* @param mapper a non-interfering, stateless function transforming {@code <T>} to {@code Stream<R>}
* @return the new {@link EmeticStream}
*
* @see Stream#flatMap(java.util.function.Function)
*
* @since 0.2.0
*/
public default <R> EmeticStream<R> flatMap(CheckedFunction<? super T, ? extends Stream<? extends R>, ?> mapper)
{
return emesis(mapToStream().flatMap(uncheckFunction(mapper)));
}
/**
* @param mapper a non-interfering, stateless function transforming {@code <T>} to {@code DoubleStream}
* @return the new {@link DoubleStream}
*
* @see Stream#flatMapToDouble(java.util.function.Function)
*
* @since 0.2.0
*/
public default DoubleStream flatMapToDouble(CheckedFunction<? super T, ? extends DoubleStream, ?> mapper)
{
return mapToStream().flatMapToDouble(uncheckFunction(mapper));
}
/**
* @param mapper a non-interfering, stateless function transforming {@code <T>} to {@code IntStream}
* @return the new {@link IntStream}
*
* @see Stream#flatMapToInt(java.util.function.Function)
*
* @since 0.2.0
*/
public default IntStream flatMapToInt(CheckedFunction<? super T, ? extends IntStream, ?> mapper)
{
return mapToStream().flatMapToInt(uncheckFunction(mapper));
}
/**
* @param mapper a non-interfering, stateless function transforming {@code <T>} to {@code LongStream}
* @return the new {@link EmeticStream}
*
* @see Stream#flatMapToLong(java.util.function.Function)
*
* @since 0.2.0
*/
public default LongStream flatMapToLong(CheckedFunction<? super T, ? extends LongStream, ?> mapper)
{
return mapToStream().flatMapToLong(uncheckFunction(mapper));
}
/**
* @param action a non-interfering action to apply to each element
* @see Stream#forEach(java.util.function.Consumer)
*
* @since 0.2.0
*/
public default void forEach(CheckedConsumer<? super T, ?> action)
{
mapToStream().forEach(uncheckConsumer(action));
}
/**
* @param action a non-interfering action to apply to each element
* @see Stream#forEachOrdered(java.util.function.Consumer)
*
* @since 0.2.0
*/
public default void forEachOrdered(CheckedConsumer<? super T, ?> action)
{
mapToStream().forEachOrdered(uncheckConsumer(action));
}
/**
* @param <R> the element type of returned {@link Stream}
*
* @param mapper a non-interfering, stateless function transforming {@code <T>} to {@code <R>}
* @return the new {@link EmeticStream}
*
* @see Stream#map(java.util.function.Function)
*
* @since 0.2.0
*/
public default <R> EmeticStream<R> map(CheckedFunction<? super T, ? extends R, ?> mapper)
{
return emesis(mapToStream().map(uncheckFunction(mapper)));
}
/**
* @param mapper a non-interfering, stateless function transforming {@code <T>} to {@code double}
* @return the new {@link EmeticStream}
*
* @see Stream#mapToDouble(java.util.function.ToDoubleFunction)
*
* @since 0.2.0
*/
public default DoubleStream mapToDouble(CheckedToDoubleFunction<? super T, ?> mapper)
{
return mapToStream().mapToDouble(uncheckToDoubleFunction(mapper));
}
/**
* @param mapper a non-interfering, stateless function transforming {@code <T>} to {@code int}
* @return the new {@link EmeticStream}
*
* @see Stream#mapToInt(java.util.function.ToIntFunction)
*
* @since 0.2.0
*/
public default IntStream mapToInt(CheckedToIntFunction<? super T, ?> mapper)
{
return mapToStream().mapToInt(uncheckToIntFunction(mapper));
}
/**
* @param mapper a non-interfering, stateless function transforming {@code <T>} to {@code long}
* @return the new {@link EmeticStream}
*
* @see Stream#mapToLong(java.util.function.ToLongFunction)
*
* @since 0.2.0
*/
public default LongStream mapToLong(CheckedToLongFunction<? super T, ?> mapper)
{
return mapToStream().mapToLong(uncheckToLongFunction(mapper));
}
/**
* @param comparator a non-interfering, stateless comparator
* @return an {@link Optional} as per {@link Stream#max(java.util.Comparator)}
*
* @see Stream#max(java.util.Comparator)
*
* @since 0.2.0
*/
public default Optional<T> max(CheckedComparator<? super T, ?> comparator)
{
return mapToStream().max(uncheckComparator(comparator));
}
/**
* @param comparator a non-interfering, stateless comparator
* @return an {@link Optional} as per {@link Stream#max(java.util.Comparator)}
*
* @see Stream#min(java.util.Comparator)
*
* @since 0.2.0
*/
public default Optional<T> min(CheckedComparator<? super T, ?> comparator)
{
return mapToStream().min(uncheckComparator(comparator));
}
/**
* @param predicate a non-interfering, stateless, checked predicate 𝗣 to apply
* to all elements in the stream 𝕊
*
* @return ∄ e ∈ 𝕊: 𝗣(e)
*
* @see Stream#noneMatch(java.util.function.Predicate)
*
* @since 0.2.0
*/
public default boolean noneMatch(CheckedPredicate<? super T, ?> predicate)
{
return mapToStream().noneMatch(uncheckPredicate(predicate));
}
/**
* @param action non-interfering action applied to elements of the underlying Stream
* @return the new EmeticStream
*
* @see Stream#peek(java.util.function.Consumer)
*
* @since 0.2.0
*/
public default EmeticStream<T> peek(CheckedConsumer<? super T, ?> action)
{
return emesis(mapToStream().peek(uncheckConsumer(action)));
}
/**
*
* @param accumulator an associative, non-interfering and stateless function
* @return the reduction
*
* @see Stream#reduce(java.util.function.BinaryOperator)
*
* @since 0.2.0
*/
public default Optional<T> reduce(CheckedBinaryOperator<T, ?> accumulator)
{
return mapToStream().reduce(uncheckBinaryOperator(accumulator));
}
/**
*
* @param identity seed value for accumulator
* @param accumulator an associative, non-interfering and stateless function
* @return the reduction
*
* @see Stream#reduce(Object, java.util.function.BinaryOperator)
*
* @since 0.2.0
*/
public default T reduce(T identity, CheckedBinaryOperator<T, ?> accumulator)
{
return mapToStream().reduce(identity, uncheckBinaryOperator(accumulator));
}
/**
*
* @param comparator non-interfering, stateless comparator to sort
* @return an emetic stream wrapping the underlying sorted stream
*
* @see Stream#sorted(java.util.Comparator)
*
* @since 0.2.0
*/
public default EmeticStream<T> sorted(CheckedComparator<? super T, ?> comparator)
{
return emesis(mapToStream().sorted(Exceptional.uncheckComparator(comparator)));
}
/**
* @return count of elements in this stream
*
* @see Stream#count()
*
* @since 0.2.0
*/
public default long count()
{
return mapToStream().count();
}
/**
* Returns an equivalent stream with the additional close handler.
*
* @param closeHandler A runnable executed when the stream is closed
* @return a stream with a handler registered
*
* @see java.util.stream.BaseStream#onClose(Runnable)
*
* @since 0.5.0
*/
public default EmeticStream<T> onClose(Runnable closeHandler)
{
return emesis(mapToStream().onClose(closeHandler));
}
/**
* Closes the wrapped stream, invoking all registered close handlers.
*
* @see AutoCloseable#close()
* @see java.util.stream.BaseStream#unordered()
*
* @since 0.5.0
*/
@Override
public default void close()
{
mapToStream().close();
}
}