package com.annimon.stream; import com.annimon.stream.function.*; import com.annimon.stream.internal.Compose; import com.annimon.stream.internal.Operators; import com.annimon.stream.internal.Params; import com.annimon.stream.iterator.IndexedIterator; import com.annimon.stream.iterator.LazyIterator; import com.annimon.stream.operator.*; import java.io.Closeable; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; /** * A sequence of elements supporting aggregate operations. * * @param <T> the type of the stream elements */ public class Stream<T> implements Closeable { /** * Returns an empty stream. * * @param <T> the type of the stream elements * @return the new empty stream */ public static <T> Stream<T> empty() { return of(Collections.<T>emptyList()); } /** * Creates a {@code Stream} from {@code Map} entries. * * @param <K> the type of map keys * @param <V> the type of map values * @param map the map with elements to be passed to stream * @return the new stream * @throws NullPointerException if {@code map} is null */ public static <K, V> Stream<Map.Entry<K, V>> of(Map<K, V> map) { Objects.requireNonNull(map); return new Stream<Map.Entry<K, V>>(map.entrySet()); } /** * Creates a {@code Stream} from any class that implements {@code Iterator} interface. * * @param <T> the type of the stream elements * @param iterator the iterator with elements to be passed to stream * @return the new stream * @throws NullPointerException if {@code iterator} is null */ public static <T> Stream<T> of(Iterator<? extends T> iterator) { Objects.requireNonNull(iterator); return new Stream<T>(iterator); } /** * Creates a {@code Stream} from any class that implements {@code Iterable} interface. * * @param <T> the type of the stream elements * @param iterable the {@code Iterable} with elements to be passed to stream * @return the new stream * @throws NullPointerException if {@code iterable} is null */ public static <T> Stream<T> of(Iterable<? extends T> iterable) { Objects.requireNonNull(iterable); return new Stream<T>(iterable); } /** * Creates a {@code Stream} from the specified values. * * @param <T> the type of the stream elements * @param elements the elements to be passed to stream * @return the new stream * @throws NullPointerException if {@code elements} is null */ public static <T> Stream<T> of(final T... elements) { Objects.requireNonNull(elements); if (elements.length == 0) { return Stream.<T>empty(); } return new Stream<T>(new ObjArray<T>(elements)); } /** * If specified element is null, returns an empty {@code Stream}, * otherwise returns a {@code Stream} containing a single element. * * @param <T> the type of the stream element * @param element the element to be passed to stream if it is non-null * @return the new stream * @since 1.1.5 */ @SuppressWarnings("unchecked") public static <T> Stream<T> ofNullable(T element) { return (element == null) ? Stream.<T>empty() : Stream.of(element); } /** * If specified iterable is null, returns an empty {@code Stream}, * otherwise returns a {@code Stream} containing elements of this iterable. * * @param <T> the type of the stream elements * @param iterable the {@code Iterable} with elements to be passed to stream * @return the new stream * @since 1.1.5 */ public static <T> Stream<T> ofNullable(Iterable<? extends T> iterable) { return (iterable == null) ? Stream.<T>empty() : Stream.<T>of(iterable); } /** * Creates a {@code Stream<Integer>} from not closed range * (from {@code from} inclusive to {@code to} exclusive and incremental step {@code 1}). * * @param from the initial value (inclusive) * @param to the upper bound (exclusive) * @return the new stream * @see IntStream#range(int, int) */ public static Stream<Integer> range(final int from, final int to) { return IntStream.range(from, to).boxed(); } /** * Creates a {@code Stream<Long>} from not closed range * (from {@code from} inclusive to {@code to} exclusive and incremental step {@code 1}). * * @param from the initial value (inclusive) * @param to the upper bound (exclusive) * @return the new stream */ public static Stream<Long> range(final long from, final long to) { return LongStream.range(from, to).boxed(); } /** * Creates a {@code Stream<Integer>} from closed range * (from {@code from} inclusive to {@code to} inclusive and incremental step {@code 1}). * * @param from the initial value (inclusive) * @param to the upper bound (inclusive) * @return the new stream * @see IntStream#rangeClosed(int, int) */ public static Stream<Integer> rangeClosed(final int from, final int to) { return IntStream.rangeClosed(from, to).boxed(); } /** * Creates a {@code Stream<Long>} from closed range * (from {@code from} inclusive to {@code to} inclusive and incremental step {@code 1}). * * @param from the initial value (inclusive) * @param to the upper bound (inclusive) * @return the new stream */ public static Stream<Long> rangeClosed(final long from, final long to) { return LongStream.rangeClosed(from, to).boxed(); } /** * Creates a {@code Stream} by elements that generated by {@code Supplier}. * * @param <T> the type of the stream elements * @param supplier the {@code Supplier} of generated elements * @return the new stream * @throws NullPointerException if {@code supplier} is null */ public static <T> Stream<T> generate(final Supplier<T> supplier) { Objects.requireNonNull(supplier); return new Stream<T>(new ObjGenerate<T>(supplier)); } /** * Creates a {@code Stream} by iterative application {@code UnaryOperator} function * to an initial element {@code seed}. Produces {@code Stream} consisting of * {@code seed}, {@code op(seed)}, {@code op(op(seed))}, etc. * * <p>Example: * <pre> * seed: 1 * op: (a) -> a + 5 * result: [1, 6, 11, 16, ...] * </pre> * * @param <T> the type of the stream elements * @param seed the initial value * @param op operator to produce new element by previous one * @return the new stream * @throws NullPointerException if {@code op} is null */ public static <T> Stream<T> iterate(final T seed, final UnaryOperator<T> op) { Objects.requireNonNull(op); return new Stream<T>(new ObjIterate<T>(seed, op)); } /** * Creates a {@code Stream} by iterative application {@code UnaryOperator} function * to an initial element {@code seed}, conditioned on satisfying the supplied predicate. * * <p>Example: * <pre> * seed: 0 * predicate: (a) -> a < 20 * op: (a) -> a + 5 * result: [0, 5, 10, 15] * </pre> * * @param <T> the type of the stream elements * @param seed the initial value * @param predicate a predicate to determine when the stream must terminate * @param op operator to produce new element by previous one * @return the new stream * @throws NullPointerException if {@code op} is null * @since 1.1.5 */ public static <T> Stream<T> iterate(final T seed, final Predicate<? super T> predicate, final UnaryOperator<T> op) { Objects.requireNonNull(predicate); return iterate(seed, op).takeWhile(predicate); } /** * Concatenates two streams. * * <p>Example: * <pre> * stream 1: [1, 2, 3, 4] * stream 2: [5, 6] * result: [1, 2, 3, 4, 5, 6] * </pre> * * @param <T> The type of stream elements * @param stream1 the first stream * @param stream2 the second stream * @return the new concatenated stream * @throws NullPointerException if {@code stream1} or {@code stream2} is null */ public static <T> Stream<T> concat(Stream<? extends T> stream1, Stream<? extends T> stream2) { Objects.requireNonNull(stream1); Objects.requireNonNull(stream2); Stream<T> result = new Stream<T>(new ObjConcat<T>(stream1.iterator, stream2.iterator)); return result.onClose(Compose.closeables(stream1, stream2)); } /** * Combines two streams by applying specified combiner function to each element at same position. * * <p>Example: * <pre> * combiner: (a, b) -> a + b * stream 1: [1, 2, 3, 4] * stream 2: [5, 6, 7, 8] * result: [6, 8, 10, 12] * </pre> * * @param <F> the type of first stream elements * @param <S> the type of second stream elements * @param <R> the type of elements in resulting stream * @param stream1 the first stream * @param stream2 the second stream * @param combiner the combiner function used to apply to each element * @return the new stream * @throws NullPointerException if {@code stream1} or {@code stream2} is null */ public static <F, S, R> Stream<R> zip(Stream<? extends F> stream1, Stream<? extends S> stream2, final BiFunction<? super F, ? super S, ? extends R> combiner) { Objects.requireNonNull(stream1); Objects.requireNonNull(stream2); return Stream.<F, S, R>zip(stream1.iterator, stream2.iterator, combiner); } /** * Combines two iterators to a stream by applying specified combiner function to each element at same position. * * <p>Example: * <pre> * combiner: (a, b) -> a + b * stream 1: [1, 2, 3, 4] * stream 2: [5, 6, 7, 8] * result: [6, 8, 10, 12] * </pre> * * @param <F> the type of first iterator elements * @param <S> the type of second iterator elements * @param <R> the type of elements in resulting stream * @param iterator1 the first iterator * @param iterator2 the second iterator * @param combiner the combiner function used to apply to each element * @return the new stream * @throws NullPointerException if {@code iterator1} or {@code iterator2} is null * @since 1.1.2 */ public static <F, S, R> Stream<R> zip(final Iterator<? extends F> iterator1, final Iterator<? extends S> iterator2, final BiFunction<? super F, ? super S, ? extends R> combiner) { Objects.requireNonNull(iterator1); Objects.requireNonNull(iterator2); return new Stream<R>(new ObjZip<F, S, R>(iterator1, iterator2, combiner)); } //<editor-fold defaultstate="collapsed" desc="Implementation"> private final Iterator<? extends T> iterator; private final Params params; private Stream(Iterator<? extends T> iterator) { this(null, iterator); } private Stream(Iterable<? extends T> iterable) { this(null, new LazyIterator<T>(iterable)); } private Stream(Params params, Iterable<? extends T> iterable) { this(params, new LazyIterator<T>(iterable)); } Stream(Params params, Iterator<? extends T> iterator) { this.params = params; this.iterator = iterator; } /** * Returns internal stream iterator. * * @deprecated As of release 1.1.1, replaced by {@link #iterator()} * @return internal stream iterator */ @Deprecated public Iterator<? extends T> getIterator() { return iterator; } /** * Returns internal stream iterator. * * @return internal stream iterator */ public Iterator<? extends T> iterator() { return iterator; } /** * Applies custom operator on stream. * * Transforming function can return {@code Stream} for intermediate operations, * or any value for terminal operation. * * <p>Operator examples: * <pre><code> * // Intermediate operator * public class Reverse<T> implements Function<Stream<T>, Stream<T>> { * @Override * public Stream<T> apply(Stream<T> stream) { * final Iterator<? extends T> iterator = stream.iterator(); * final ArrayDeque<T> deque = new ArrayDeque<T>(); * while (iterator.hasNext()) { * deque.addFirst(iterator.next()); * } * return Stream.of(deque.iterator()); * } * } * * // Intermediate operator based on existing stream operators * public class SkipAndLimit<T> implements UnaryOperator<Stream<T>> { * * private final int skip, limit; * * public SkipAndLimit(int skip, int limit) { * this.skip = skip; * this.limit = limit; * } * * @Override * public Stream<T> apply(Stream<T> stream) { * return stream.skip(skip).limit(limit); * } * } * * // Terminal operator * public class Sum implements Function<Stream<Integer>, Integer> { * @Override * public Integer apply(Stream<Integer> stream) { * return stream.reduce(0, new BinaryOperator<Integer>() { * @Override * public Integer apply(Integer value1, Integer value2) { * return value1 + value2; * } * }); * } * } * </code></pre> * * @param <R> the type of the result * @param function a transforming function * @return a result of the transforming function * @throws NullPointerException if {@code function} is null */ public <R> R custom(Function<Stream<T>, R> function) { Objects.requireNonNull(function); return function.apply(this); } /** * Returns {@code Stream} with elements that satisfy the given predicate. * * <p>This is an intermediate operation. * * <p>Example: * <pre> * predicate: (a) -> a > 2 * stream: [1, 2, 3, 4, -8, 0, 11] * result: [3, 4, 11] * </pre> * * @param predicate the predicate used to filter elements * @return the new stream */ public Stream<T> filter(final Predicate<? super T> predicate) { return new Stream<T>(params, new ObjFilter<T>(iterator, predicate)); } /** * Returns a {@code Stream} with elements that satisfy the given {@code IndexedPredicate}. * * <p>This is an intermediate operation. * * <p>Example: * <pre> * predicate: (index, value) -> (index + value) > 6 * stream: [1, 2, 3, 4, 0, 11] * index: [0, 1, 2, 3, 4, 5] * sum: [1, 3, 5, 7, 4, 16] * filter: [ 7, 16] * result: [4, 11] * </pre> * * @param predicate the {@code IndexedPredicate} used to filter elements * @return the new stream * @since 1.1.6 */ public Stream<T> filterIndexed(IndexedPredicate<? super T> predicate) { return filterIndexed(0, 1, predicate); } /** * Returns a {@code Stream} with elements that satisfy the given {@code IndexedPredicate}. * * <p>This is an intermediate operation. * * <p>Example: * <pre> * from: 4 * step: 3 * predicate: (index, value) -> (index + value) > 15 * stream: [1, 2, 3, 4, 0, 11] * index: [4, 7, 10, 13, 16, 19] * sum: [5, 9, 13, 17, 16, 30] * filter: [ 17, 16, 30] * result: [4, 0, 11] * </pre> * * @param from the initial value of the index (inclusive) * @param step the step of the index * @param predicate the {@code IndexedPredicate} used to filter elements * @return the new stream * @since 1.1.6 */ public Stream<T> filterIndexed(int from, int step, IndexedPredicate<? super T> predicate) { return new Stream<T>(params, new ObjFilterIndexed<T>( new IndexedIterator<T>(from, step, iterator), predicate)); } /** * Returns {@code Stream} with elements that does not satisfy the given predicate. * * <p>This is an intermediate operation. * * @param predicate the predicate used to filter elements * @return the new stream */ public Stream<T> filterNot(final Predicate<? super T> predicate) { return filter(Predicate.Util.negate(predicate)); } /** * Returns a stream consisting of the elements of this stream which are * instances of given class. * * <p>This is an intermediate operation. * * @param <TT> a type of instances to select. * @param clazz a class which instances should be selected * @return the new stream of type passed as parameter */ @SuppressWarnings("unchecked") public <TT> Stream<TT> select(final Class<TT> clazz) { return (Stream<TT>) filter(new Predicate<T>() { @Override public boolean test(T value) { return clazz.isInstance(value); } }); } /** * Returns {@code Stream} without null elements. * * <p>This is an intermediate operation. * * @return the new stream * @since 1.1.6 */ public Stream<T> withoutNulls() { return filter(Predicate.Util.<T>notNull()); } /** * Returns {@code Stream} with elements that is null only. * * <p>This is an intermediate operation. * * @return the new stream * @since 1.1.6 */ public Stream<T> nullsOnly() { return filterNot(Predicate.Util.<T>notNull()); } /** * Returns {@code Stream} with elements that obtained by applying the given function. * * <p>This is an intermediate operation. * * <p>Example: * <pre> * mapper: (a) -> a + 5 * stream: [1, 2, 3, 4] * result: [6, 7, 8, 9] * </pre> * * @param <R> the type of elements in resulting stream * @param mapper the mapper function used to apply to each element * @return the new stream */ public <R> Stream<R> map(final Function<? super T, ? extends R> mapper) { return new Stream<R>(params, new ObjMap<T, R>(iterator, mapper)); } /** * Returns a {@code Stream} with elements that obtained by applying the given {@code IndexedFunction}. * * <p>This is an intermediate operation. * * <p>Example: * <pre> * predicate: (index, value) -> (index * value) * stream: [1, 2, 3, 4] * index: [0, 1, 2, 3] * result: [0, 2, 6, 12] * </pre> * * @param <R> the type of elements in resulting stream * @param mapper the mapper function used to apply to each element * @return the new stream * @since 1.1.6 */ public <R> Stream<R> mapIndexed(IndexedFunction<? super T, ? extends R> mapper) { return this.<R>mapIndexed(0, 1, mapper); } /** * Returns a {@code Stream} with elements that obtained by applying the given {@code IndexedFunction}. * * <p>This is an intermediate operation. * * <p>Example: * <pre> * from: -2 * step: 2 * predicate: (index, value) -> (index * value) * stream: [ 1, 2, 3, 4] * index: [-2, 0, 2, 4] * result: [-2, 0, 6, 16] * </pre> * * @param <R> the type of elements in resulting stream * @param from the initial value of the index (inclusive) * @param step the step of the index * @param mapper the mapper function used to apply to each element * @return the new stream * @since 1.1.6 */ public <R> Stream<R> mapIndexed(int from, int step, IndexedFunction<? super T, ? extends R> mapper) { return new Stream<R>(params, new ObjMapIndexed<T, R>( new IndexedIterator<T>(from, step, iterator), mapper)); } /** * Returns {@code IntStream} with elements that obtained by applying the given function. * * <p>This is an intermediate operation. * * @param mapper the mapper function used to apply to each element * @return the new {@code IntStream} * @see #map(com.annimon.stream.function.Function) */ public IntStream mapToInt(final ToIntFunction<? super T> mapper) { return new IntStream(params, new ObjMapToInt<T>(iterator, mapper)); } /** * Returns {@code LongStream} with elements that obtained by applying the given function. * * <p>This is an intermediate operation. * * @param mapper the mapper function used to apply to each element * @return the new {@code LongStream} * @since 1.1.4 * @see #map(com.annimon.stream.function.Function) */ public LongStream mapToLong(final ToLongFunction<? super T> mapper) { return new LongStream(params, new ObjMapToLong<T>(iterator, mapper)); } /** * Returns {@code DoubleStream} with elements that obtained by applying the given function. * * <p>This is an intermediate operation. * * @param mapper the mapper function used to apply to each element * @return the new {@code DoubleStream} * @since 1.1.4 * @see #map(com.annimon.stream.function.Function) */ public DoubleStream mapToDouble(final ToDoubleFunction<? super T> mapper) { return new DoubleStream(params, new ObjMapToDouble<T>(iterator, mapper)); } /** * Returns a stream consisting of the results of replacing each element of * this stream with the contents of a mapped stream produced by applying * the provided mapping function to each element. * * <p>This is an intermediate operation. * * <p>Example: * <pre> * mapper: (a) -> [a, a + 5] * stream: [1, 2, 3, 4] * result: [1, 6, 2, 7, 3, 8, 4, 9] * </pre> * * @param <R> the type of elements in resulting stream * @param mapper the mapper function used to apply to each element * @return the new stream */ public <R> Stream<R> flatMap(final Function<? super T, ? extends Stream<? extends R>> mapper) { return new Stream<R>(params, new ObjFlatMap<T, R>(iterator, mapper)); } /** * Returns a stream consisting of the results of replacing each element of * this stream with the contents of a mapped stream produced by applying * the provided mapping function to each element. * * <p>This is an intermediate operation. * * @param mapper the mapper function used to apply to each element * @return the new {@code IntStream} * @see #flatMap(com.annimon.stream.function.Function) */ public IntStream flatMapToInt(final Function<? super T, ? extends IntStream> mapper) { return new IntStream(params, new ObjFlatMapToInt<T>(iterator, mapper)); } /** * Returns a stream consisting of the results of replacing each element of * this stream with the contents of a mapped stream produced by applying * the provided mapping function to each element. * * <p>This is an intermediate operation. * * @param mapper the mapper function used to apply to each element * @return the new {@code LongStream} * @see #flatMap(com.annimon.stream.function.Function) */ public LongStream flatMapToLong(final Function<? super T, ? extends LongStream> mapper) { return new LongStream(params, new ObjFlatMapToLong<T>(iterator, mapper)); } /** * Returns a stream consisting of the results of replacing each element of * this stream with the contents of a mapped stream produced by applying * the provided mapping function to each element. * * <p>This is an intermediate operation. * * @param mapper the mapper function used to apply to each element * @return the new {@code DoubleStream} * @see #flatMap(com.annimon.stream.function.Function) */ public DoubleStream flatMapToDouble(final Function<? super T, ? extends DoubleStream> mapper) { return new DoubleStream(params, new ObjFlatMapToDouble<T>(iterator, mapper)); } /** * Returns {@code Stream} with indexed elements. * Indexing starts from 0 with step 1. * * <p>This is an intermediate operation. * * <p>Example: * <pre> * stream: ["a", "b", "c"] * result: [(0, "a"), (1, "b"), (2, "c")] * </pre> * * @return the new {@code IntPair} stream * @since 1.1.2 */ public Stream<IntPair<T>> indexed() { return indexed(0, 1); } /** * Returns {@code Stream} with indexed elements. * * <p>This is an intermediate operation. * * <p>Example: * <pre> * from: 5, step: 10 * stream: ["a", "b", "c"] * result: [(5, "a"), (15, "b"), (25, "c")] * </pre> * * @param from the initial value (inclusive) * @param step the step * @return the new {@code IntPair} stream * @since 1.1.2 */ public Stream<IntPair<T>> indexed(final int from, final int step) { return mapIndexed(from, step, new IndexedFunction<T, IntPair<T>>() { @Override public IntPair<T> apply(int index, T t) { return new IntPair<T>(index, t); } }); } /** * Returns {@code Stream} with distinct elements (as determinated by {@code hashCode} and {@code equals} methods). * * <p>This is a stateful intermediate operation. * * <p>Example: * <pre> * stream: [1, 4, 2, 3, 3, 4, 1] * result: [1, 4, 2, 3] * </pre> * * @return the new stream */ public Stream<T> distinct() { return new Stream<T>(params, new ObjDistinct<T>(iterator)); } /** * Returns {@code Stream} with sorted elements (as determinated by {@link Comparable} interface). * * <p>This is a stateful intermediate operation. * <p>If the elements of this stream are not {@link Comparable}, * a {@code java.lang.ClassCastException} may be thrown when the terminal operation is executed. * * <p>Example: * <pre> * stream: [3, 4, 1, 2] * result: [1, 2, 3, 4] * </pre> * * @return the new stream */ public Stream<T> sorted() { return sorted(new Comparator<T>() { @SuppressWarnings("unchecked") @Override public int compare(T o1, T o2) { Comparable c1 = (Comparable) o1; Comparable c2 = (Comparable) o2; return c1.compareTo(c2); } }); } /** * Returns {@code Stream} with sorted elements (as determinated by provided {@code Comparator}). * * <p>This is a stateful intermediate operation. * * <p>Example: * <pre> * comparator: (a, b) -> -a.compareTo(b) * stream: [1, 2, 3, 4] * result: [4, 3, 2, 1] * </pre> * * @param comparator the {@code Comparator} to compare elements * @return the new stream */ public Stream<T> sorted(final Comparator<? super T> comparator) { return new Stream<T>(params, new ObjSorted<T>(iterator, comparator)); } /** * Returns {@code Stream} with sorted elements (as determinated by {@code Comparable} interface). * Each element transformed by given function {@code f} before comparing. * * <p>This is a stateful intermediate operation. * * <p>Example: * <pre> * f: (a) -> -a * stream: [1, 2, 3, 4] * result: [4, 3, 2, 1] * </pre> * * @param <R> the type of the result of transforming function * @param f the transformation function * @return the new stream */ public <R extends Comparable<? super R>> Stream<T> sortBy(final Function<? super T, ? extends R> f) { return sorted(ComparatorCompat.comparing(f)); } /** * Partitions {@code Stream} into {@code Map} entries according to the given classifier function. * * <p>This is a stateful intermediate operation. * * <p>Example: * <pre> * classifier: (str) -> str.length() * stream: ["a", "bc", "d", "ef", "ghij"] * result: [{1: ["a", "d"]}, {2: ["bc", "ef"]}, {4: ["ghij"]}] * </pre> * * @param <K> the type of the keys, which are result of the classifier function * @param classifier the classifier function * @return the new stream */ public <K> Stream<Map.Entry<K, List<T>>> groupBy(final Function<? super T, ? extends K> classifier) { Map<K, List<T>> map = collect(Collectors.<T, K>groupingBy(classifier)); return new Stream<Map.Entry<K, List<T>>>(params, map.entrySet()); } /** * Partitions {@code Stream} into {@code List}s according to the given classifier function. In contrast * to {@link #groupBy(Function)}, this method assumes that the elements of the stream are sorted. * Because of this assumption, it does not need to first collect all elements and then partition them. * Instead, it can emit a {@code List} of elements when it reaches the first element that does not * belong to the same chunk as the previous elements. * * <p>This is an intermediate operation. * * <p>Example: * <pre> * classifier: (a) -> a % 5 == 0 * stream: [1, 2, 5, 6, 7, 9, 10, 12, 14] * result: [[1, 2], [5], [6, 7, 9], [10], [12, 14]] * </pre> * * @param <K> the type of the keys, which are the result of the classifier function * @param classifier the classifier function * @return the new stream */ public <K> Stream<List<T>> chunkBy(final Function<? super T, ? extends K> classifier) { return new Stream<List<T>>(params, new ObjChunkBy<T, K>(iterator, classifier)); } /** * Samples the {@code Stream} by emitting every n-th element. * * <p>This is an intermediate operation. * * <p>Example: * <pre> * stepWidth: 3 * stream: [1, 2, 3, 4, 5, 6, 7, 8] * result: [1, 4, 7] * </pre> * * @param stepWidth step width * @return the new stream * @throws IllegalArgumentException if {@code stepWidth} is zero or negative */ public Stream<T> sample(final int stepWidth) { if (stepWidth <= 0) throw new IllegalArgumentException("stepWidth cannot be zero or negative"); if (stepWidth == 1) return this; return slidingWindow(1, stepWidth).map(new Function<List<T>, T>() { @Override public T apply(List<T> list) { return list.get(0); } }); } /** * Partitions {@code Stream} into {@code List}s of fixed size by sliding over the elements of the stream. * It starts with the first element and in each iteration moves by 1. This method yields the same results * as calling {@link #slidingWindow(int, int)} with a {@code stepWidth} of 1. * * <p>This is an intermediate operation. * * <p>Example: * <pre> * windowSize: 3 * stream: [1, 2, 3, 4, 5] * result: [[1, 2, 3], [2, 3, 4], [3, 4, 5]] * </pre> * * @param windowSize number of elements that will be emitted together in a list * @return the new stream * @see #slidingWindow(int, int) */ public Stream<List<T>> slidingWindow(final int windowSize) { return slidingWindow(windowSize, 1); } /** * Partitions {@code Stream} into {@code List}s of fixed size by sliding over the elements of the stream. * It starts with the first element and in each iteration moves by the given step width. This method * allows, for example, to partition the elements into batches of {@code windowSize} elements (by using a * step width equal to the specified window size) or to sample every n-th element (by using a window size * of 1 and a step width of n). * * <p>This is an intermediate operation. * * <p>Example: * <pre> * windowSize: 3, stepWidth: 3 * stream: [1, 1, 1, 2, 2, 2, 3, 3, 3] * result: [[1, 1, 1], [2, 2, 2] [3, 3, 3]] * * windowSize: 2, stepWidth: 3 * stream: [1, 2, 3, 1, 2, 3, 1, 2, 3] * result: [[1, 2], [1, 2], [1, 2]] * * windowSize: 3, stepWidth: 1 * stream: [1, 2, 3, 4, 5, 6] * result: [[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6]] * </pre> * * @param windowSize number of elements that will be emitted together in a list * @param stepWidth step width * @return the new stream * @throws IllegalArgumentException if {@code windowSize} is zero or negative * @throws IllegalArgumentException if {@code stepWidth} is zero or negative */ public Stream<List<T>> slidingWindow(final int windowSize, final int stepWidth) { if (windowSize <= 0) throw new IllegalArgumentException("windowSize cannot be zero or negative"); if (stepWidth <= 0) throw new IllegalArgumentException("stepWidth cannot be zero or negative"); return new Stream<List<T>>(params, new ObjSlidingWindow<T>(iterator, windowSize, stepWidth)); } /** * Performs provided action on each element. * * <p>This is an intermediate operation. * * @param action the action to be performed on each element * @return the new stream */ public Stream<T> peek(final Consumer<? super T> action) { return new Stream<T>(params, new ObjPeek<T>(iterator, action)); } /** * Returns a {@code Stream} produced by iterative application of a accumulation function * to reduction value and next element of the current stream. * Produces a {@code Stream} consisting of {@code value1}, {@code acc(value1, value2)}, * {@code acc(acc(value1, value2), value3)}, etc. * * <p>This is an intermediate operation. * * <p>Example: * <pre> * accumulator: (a, b) -> a + b * stream: [1, 2, 3, 4, 5] * result: [1, 3, 6, 10, 15] * </pre> * * @param accumulator the accumulation function * @return the new stream * @throws NullPointerException if {@code accumulator} is null * @since 1.1.6 */ public Stream<T> scan(final BiFunction<T, T, T> accumulator) { Objects.requireNonNull(accumulator); return new Stream<T>(params, new ObjScan<T>(iterator, accumulator)); } /** * Returns a {@code Stream} produced by iterative application of a accumulation function * to an initial element {@code identity} and next element of the current stream. * Produces a {@code Stream} consisting of {@code identity}, {@code acc(identity, value1)}, * {@code acc(acc(identity, value1), value2)}, etc. * * <p>This is an intermediate operation. * * <p>Example: * <pre> * identity: 0 * accumulator: (a, b) -> a + b * stream: [1, 2, 3, 4, 5] * result: [0, 1, 3, 6, 10, 15] * </pre> * * @param <R> the type of the result * @param identity the initial value * @param accumulator the accumulation function * @return the new stream * @throws NullPointerException if {@code accumulator} is null * @since 1.1.6 */ public <R> Stream<R> scan(final R identity, final BiFunction<? super R, ? super T, ? extends R> accumulator) { Objects.requireNonNull(accumulator); return new Stream<R>(params, new ObjScanIdentity<T, R>(iterator, identity, accumulator)); } /** * Takes elements while the predicate returns {@code true}. * * <p>This is an intermediate operation. * * <p>Example: * <pre> * predicate: (a) -> a < 3 * stream: [1, 2, 3, 4, 1, 2, 3, 4] * result: [1, 2] * </pre> * * @param predicate the predicate used to take elements * @return the new stream */ public Stream<T> takeWhile(final Predicate<? super T> predicate) { return new Stream<T>(params, new ObjTakeWhile<T>(iterator, predicate)); } /** * Takes elements while the {@code IndexedPredicate} returns {@code true}. * * <p>This is an intermediate operation. * * <p>Example: * <pre> * predicate: (index, value) -> (index + value) < 5 * stream: [1, 2, 3, 4, -5, -6, -7] * index: [0, 1, 2, 3, 4, 5, 6] * sum: [1, 3, 5, 7, -1, -1, -1] * result: [1, 2] * </pre> * * @param predicate the {@code IndexedPredicate} used to take elements * @return the new stream * @since 1.1.6 */ public Stream<T> takeWhileIndexed(IndexedPredicate<? super T> predicate) { return takeWhileIndexed(0, 1, predicate); } /** * Takes elements while the {@code IndexedPredicate} returns {@code true}. * * <p>This is an intermediate operation. * * <p>Example: * <pre> * from: 2 * step: 2 * predicate: (index, value) -> (index + value) < 8 * stream: [1, 2, 3, 4, -5, -6, -7] * index: [2, 4, 6, 8, 10, 12, 14] * sum: [3, 6, 9, 12, 5, 6, 7] * result: [1, 2] * </pre> * * @param from the initial value of the index (inclusive) * @param step the step of the index * @param predicate the {@code IndexedPredicate} used to take elements * @return the new stream * @since 1.1.6 */ public Stream<T> takeWhileIndexed(int from, int step, IndexedPredicate<? super T> predicate) { return new Stream<T>(params, new ObjTakeWhileIndexed<T>( new IndexedIterator<T>(from, step, iterator), predicate)); } /** * Takes elements while the predicate returns {@code false}. * Once predicate condition is satisfied by an element, the stream * finishes with this element. * * <p>This is an intermediate operation. * * <p>Example: * <pre> * stopPredicate: (a) -> a > 2 * stream: [1, 2, 3, 4, 1, 2, 3, 4] * result: [1, 2, 3] * </pre> * * @param stopPredicate the predicate used to take elements * @return the new stream * @since 1.1.6 */ public Stream<T> takeUntil(final Predicate<? super T> stopPredicate) { return new Stream<T>(params, new ObjTakeUntil<T>(iterator, stopPredicate)); } /** * Takes elements while the {@code IndexedPredicate} returns {@code false}. * Once predicate condition is satisfied by an element, the stream * finishes with this element. * * <p>This is an intermediate operation. * * <p>Example: * <pre> * stopPredicate: (index, value) -> (index + value) > 4 * stream: [1, 2, 3, 4, 0, 1, 2] * index: [0, 1, 2, 3, 4, 5, 6] * sum: [1, 3, 5, 7, 4, 6, 8] * result: [1, 2, 3] * </pre> * * @param stopPredicate the {@code IndexedPredicate} used to take elements * @return the new stream * @since 1.1.6 */ public Stream<T> takeUntilIndexed(IndexedPredicate<? super T> stopPredicate) { return takeUntilIndexed(0, 1, stopPredicate); } /** * Takes elements while the {@code IndexedPredicate} returns {@code false}. * Once predicate condition is satisfied by an element, the stream * finishes with this element. * * <p>This is an intermediate operation. * * <p>Example: * <pre> * from: 2 * step: 2 * stopPredicate: (index, value) -> (index + value) > 8 * stream: [1, 2, 3, 4, 0, 1, 2] * index: [2, 4, 6, 8, 10, 11, 14] * sum: [3, 6, 9, 12, 10, 12, 16] * result: [1, 2, 3] * </pre> * * @param from the initial value of the index (inclusive) * @param step the step of the index * @param stopPredicate the {@code IndexedPredicate} used to take elements * @return the new stream * @since 1.1.6 */ public Stream<T> takeUntilIndexed(int from, int step, IndexedPredicate<? super T> stopPredicate) { return new Stream<T>(params, new ObjTakeUntilIndexed<T>( new IndexedIterator<T>(from, step, iterator), stopPredicate)); } /** * Drops elements while the predicate is true, then returns the rest. * * <p>This is an intermediate operation. * * <p>Example: * <pre> * predicate: (a) -> a < 3 * stream: [1, 2, 3, 4, 1, 2, 3, 4] * result: [3, 4, 1, 2, 3, 4] * </pre> * * @param predicate the predicate used to drop elements * @return the new stream */ public Stream<T> dropWhile(final Predicate<? super T> predicate) { return new Stream<T>(params, new ObjDropWhile<T>(iterator, predicate)); } /** * Drops elements while the {@code IndexedPredicate} is true, then returns the rest. * * <p>This is an intermediate operation. * * <p>Example: * <pre> * predicate: (index, value) -> (index + value) < 5 * stream: [1, 2, 3, 4, 0, 1, 2] * index: [0, 1, 2, 3, 4, 5, 6] * sum: [1, 3, 5, 7, 4, 6, 8] * result: [3, 4, 0, 1, 2] * </pre> * * @param predicate the {@code IndexedPredicate} used to drop elements * @return the new stream * @since 1.1.6 */ public Stream<T> dropWhileIndexed(IndexedPredicate<? super T> predicate) { return dropWhileIndexed(0, 1, predicate); } /** * Drops elements while the {@code IndexedPredicate} is true, then returns the rest. * * <p>This is an intermediate operation. * * <p>Example: * <pre> * from: 2 * step: 2 * predicate: (index, value) -> (index + value) < 10 * stream: [1, 2, 3, 4, -5, -6, -7] * index: [2, 4, 6, 8, 10, 12, 14] * sum: [3, 6, 9, 12, 5, 6, 7] * result: [4, -5, -6, -7] * </pre> * * @param from the initial value of the index (inclusive) * @param step the step of the index * @param predicate the {@code IndexedPredicate} used to drop elements * @return the new stream * @since 1.1.6 */ public Stream<T> dropWhileIndexed(int from, int step, IndexedPredicate<? super T> predicate) { return new Stream<T>(params, new ObjDropWhileIndexed<T>( new IndexedIterator<T>(from, step, iterator), predicate)); } /** * Returns {@code Stream} with first {@code maxSize} elements. * * <p>This is a short-circuiting stateful intermediate operation. * * <p>Example: * <pre> * maxSize: 3 * stream: [1, 2, 3, 4, 5] * result: [1, 2, 3] * * maxSize: 10 * stream: [1, 2] * result: [1, 2] * </pre> * * @param maxSize the number of elements to limit * @return the new stream * @throws IllegalArgumentException if {@code maxSize} is negative */ public Stream<T> limit(final long maxSize) { if (maxSize < 0) { throw new IllegalArgumentException("maxSize cannot be negative"); } if (maxSize == 0) { return Stream.empty(); } return new Stream<T>(params, new ObjLimit<T>(iterator, maxSize)); } /** * Skips first {@code n} elements and returns {@code Stream} with remaining elements. * If stream contains fewer than {@code n} elements, then an empty stream will be returned. * * <p>This is a stateful intermediate operation. * * <p>Example: * <pre> * n: 3 * stream: [1, 2, 3, 4, 5] * result: [4, 5] * * n: 10 * stream: [1, 2] * result: [] * </pre> * * @param n the number of elements to skip * @return the new stream * @throws IllegalArgumentException if {@code n} is negative */ public Stream<T> skip(final long n) { if (n < 0) throw new IllegalArgumentException("n cannot be negative"); if (n == 0) return this; return new Stream<T>(params, new ObjSkip<T>(iterator, n)); } /** * Performs the given action on each element. * * <p>This is a terminal operation. * * @param action the action to be performed on each element */ public void forEach(final Consumer<? super T> action) { while (iterator.hasNext()) { action.accept(iterator.next()); } } /** * Performs the given indexed action on each element. * * <p>This is a terminal operation. * * @param action the action to be performed on each element * @since 1.1.6 */ public void forEachIndexed(IndexedConsumer<? super T> action) { forEachIndexed(0, 1, action); } /** * Performs the given indexed action on each element. * * <p>This is a terminal operation. * * @param from the initial value of the index (inclusive) * @param step the step of the index * @param action the action to be performed on each element * @since 1.1.6 */ public void forEachIndexed(int from, int step, IndexedConsumer<? super T> action) { int index = from; while (iterator.hasNext()) { action.accept(index, iterator.next()); index += step; } } /** * Reduces the elements using provided identity value and the associative accumulation function. * * <p>This is a terminal operation. * * <p>Example: * <pre> * identity: 0 * accumulator: (a, b) -> a + b * stream: [1, 2, 3, 4, 5] * result: 15 * </pre> * * @param <R> the type of the result * @param identity the initial value * @param accumulator the accumulation function * @return the result of the reduction */ public <R> R reduce(R identity, BiFunction<? super R, ? super T, ? extends R> accumulator) { R result = identity; while (iterator.hasNext()) { final T value = iterator.next(); result = accumulator.apply(result, value); } return result; } /** * Reduces the elements using provided identity value and * the associative accumulation indexed function. * * <p>This is a terminal operation. * * <p>Example: * <pre> * identity: 10 * accumulator: (index, a, b) -> index + a + b * stream: [1, 2, 3, 4, 5] * index: [0, 1, 2, 3, 4] * result: 10 + 1 + 3 + 5 + 7 + 9 = 35 * </pre> * * @param <R> the type of the result * @param identity the initial value * @param accumulator the accumulation function * @return the result of the reduction * @since 1.1.6 */ public <R> R reduceIndexed(R identity, IndexedBiFunction<? super R, ? super T, ? extends R> accumulator) { return reduceIndexed(0, 1, identity, accumulator); } /** * Reduces the elements using provided identity value and * the associative accumulation indexed function. * * <p>This is a terminal operation. * * <p>Example: * <pre> * from: 1 * step: 2 * identity: 10 * accumulator: (index, a, b) -> index + a + b * stream: [1, 2, 3, 4, 5] * index: [1, 3, 5, 7, 9] * result: 10 + 2 + 5 + 8 + 11 + 14 = 50 * </pre> * * @param <R> the type of the result * @param from the initial value of the index (inclusive) * @param step the step of the index * @param identity the initial value * @param accumulator the accumulation function * @return the result of the reduction * @since 1.1.6 */ public <R> R reduceIndexed(int from, int step, R identity, IndexedBiFunction<? super R, ? super T, ? extends R> accumulator) { R result = identity; int index = from; while (iterator.hasNext()) { final T value = iterator.next(); result = accumulator.apply(index, result, value); index += step; } return result; } /** * Reduces the elements using provided associative accumulation function. * * <p>This is a terminal operation. * * @param accumulator the accumulation function * @return the result of the reduction * @see #reduce(java.lang.Object, com.annimon.stream.function.BiFunction) */ public Optional<T> reduce(BiFunction<T, T, T> accumulator) { boolean foundAny = false; T result = null; while (iterator.hasNext()) { final T value = iterator.next(); if (!foundAny) { foundAny = true; result = value; } else { result = accumulator.apply(result, value); } } return foundAny ? Optional.of(result) : Optional.<T>empty(); } /** * Collects elements to an array. * * <p>This is a terminal operation. * * @return the result of collect elements * @see #toArray(com.annimon.stream.function.IntFunction) */ public Object[] toArray() { return toArray(new IntFunction<Object[]>() { @Override public Object[] apply(int value) { return new Object[value]; } }); } /** * Collects elements to an array, the {@code generator} constructor of provided. * * <p>This is a terminal operation. * * @param <R> the type of the result * @param generator the array constructor reference that accommodates future array of assigned size * @return the result of collect elements */ public <R> R[] toArray(IntFunction<R[]> generator) { return Operators.toArray(iterator, generator); } /** * Collects elements to a new {@code List}. * * <p>This implementation <strong>does not</strong> call {@code collect(Collectors.toList())}, so * it can be faster by reducing method calls. * * <p>This is a terminal operation. * * @return a new {@code List} * @since 1.1.5 * @see Collectors#toList() */ public List<T> toList() { final List<T> result = new ArrayList<T>(); while (iterator.hasNext()) { result.add(iterator.next()); } return result; } /** * Collects elements to {@code supplier} provided container by applying the given accumulation function. * * <p>This is a terminal operation. * * @param <R> the type of the result * @param supplier the supplier function that provides container * @param accumulator the accumulation function * @return the result of collect elements * @see #collect(com.annimon.stream.Collector) */ public <R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator) { final R result = supplier.get(); while (iterator.hasNext()) { final T value = iterator.next(); accumulator.accept(result, value); } return result; } /** * Collects elements with {@code collector} that encapsulates supplier, accumulator and combiner functions. * * <p>This is a terminal operation. * * @param <R> the type of result * @param <A> the intermediate used by {@code Collector} * @param collector the {@code Collector} * @return the result of collect elements * @see #collect(com.annimon.stream.function.Supplier, com.annimon.stream.function.BiConsumer) */ public <R, A> R collect(Collector<? super T, A, R> collector) { A container = collector.supplier().get(); while (iterator.hasNext()) { final T value = iterator.next(); collector.accumulator().accept(container, value); } if (collector.finisher() != null) return collector.finisher().apply(container); return Collectors.<A, R>castIdentity().apply(container); } /** * Finds the minimum element according to the given comparator. * * <p>This is a terminal operation. * * <p>Example: * <pre> * comparator: (a, b) -> a.compareTo(b) * stream: [1, 2, 3, 4, 5] * result: 1 * </pre> * * @param comparator the {@code Comparator} to compare elements * @return the minimum element */ public Optional<T> min(Comparator<? super T> comparator) { return reduce(BinaryOperator.Util.<T>minBy(comparator)); } /** * Finds the maximum element according to the given comparator. * * <p>This is a terminal operation. * * <p>Example: * <pre> * comparator: (a, b) -> a.compareTo(b) * stream: [1, 2, 3, 4, 5] * result: 5 * </pre> * * @param comparator the {@code Comparator} to compare elements * @return the maximum element */ public Optional<T> max(Comparator<? super T> comparator) { return reduce(BinaryOperator.Util.<T>maxBy(comparator)); } /** * Returns the count of elements in this stream. * * <p>This is a terminal operation. * * @return the count of elements */ public long count() { long count = 0; while (iterator.hasNext()) { iterator.next(); count++; } return count; } /** * Tests whether any elements match the given predicate. * * <p>This is a short-circuiting terminal operation. * * <p>Example: * <pre> * predicate: (a) -> a == 5 * stream: [1, 2, 3, 4, 5] * result: true * * predicate: (a) -> a == 5 * stream: [5, 5, 5] * result: true * </pre> * * @param predicate the predicate used to match elements * @return {@code true} if any elements match the given predicate, otherwise {@code false} */ public boolean anyMatch(Predicate<? super T> predicate) { return match(predicate, MATCH_ANY); } /** * Tests whether all elements match the given predicate. * * <p>This is a short-circuiting terminal operation. * * <p>Example: * <pre> * predicate: (a) -> a == 5 * stream: [1, 2, 3, 4, 5] * result: false * * predicate: (a) -> a == 5 * stream: [5, 5, 5] * result: true * </pre> * * @param predicate the predicate used to match elements * @return {@code true} if all elements match the given predicate, otherwise {@code false} */ public boolean allMatch(Predicate<? super T> predicate) { return match(predicate, MATCH_ALL); } /** * Tests whether no elements match the given predicate. * * <p>This is a short-circuiting terminal operation. * * <p>Example: * <pre> * predicate: (a) -> a == 5 * stream: [1, 2, 3, 4, 5] * result: false * * predicate: (a) -> a == 5 * stream: [1, 2, 3] * result: true * </pre> * * @param predicate the predicate used to match elements * @return {@code true} if no elements match the given predicate, otherwise {@code false} */ public boolean noneMatch(Predicate<? super T> predicate) { return match(predicate, MATCH_NONE); } /** * Finds the first element and its index that matches the given predicate. * * <p>This is a short-circuiting terminal operation. * * <p>Example: * <pre> * predicate: (index, value) -> index + value == 7 * stream: [1, 2, 3, 4, 5, 2, 0] * index: [0, 1, 2, 3, 4, 5, 6] * result: Optional.of(IntPair(3, 4)) * </pre> * * @param predicate the predicate to find value * @return an {@code Optional} with {@code IntPair} * or {@code Optional.empty()} if stream is empty or no value was found. * @since 1.1.8 */ public Optional<IntPair<T>> findIndexed(IndexedPredicate<? super T> predicate) { return findIndexed(0, 1, predicate); } /** * Finds the first element and its index that matches the given predicate. * * <p>This is a short-circuiting terminal operation. * * <p>Example: * <pre> * from: 0 * step: 10 * predicate: (index, value) -> index + value == 42 * stream: [1, 11, 22, 12, 40] * index: [0, 10, 20, 30, 40] * result: Optional.of(IntPair(20, 22)) * </pre> * * @param from the initial value of the index (inclusive) * @param step the step of the index * @param predicate the predicate to find value * @return an {@code Optional} with {@code IntPair} * or {@code Optional.empty()} if stream is empty or no value was found. * @since 1.1.8 */ public Optional<IntPair<T>> findIndexed(int from, int step, IndexedPredicate<? super T> predicate) { int index = from; while (iterator.hasNext()) { final T value = iterator.next(); if (predicate.test(index, value)) { return Optional.of(new IntPair<T>(index, value)); } index += step; } return Optional.empty(); } /** * Returns the first element wrapped by {@code Optional} class. * If stream is empty, returns {@code Optional.empty()}. * * <p>This is a short-circuiting terminal operation. * * @return an {@code Optional} with first element * or {@code Optional.empty()} if stream is empty */ public Optional<T> findFirst() { if (iterator.hasNext()) { return Optional.of(iterator.next()); } return Optional.empty(); } /** * Returns the single element of stream. * If stream is empty, throws {@code NoSuchElementException}. * If stream contains more than one element, throws {@code IllegalStateException}. * * <p>This is a short-circuiting terminal operation. * * <p>Example: * <pre> * stream: [] * result: NoSuchElementException * * stream: [1] * result: 1 * * stream: [1, 2, 3] * result: IllegalStateException * </pre> * * @return single element of stream * @throws NoSuchElementException if stream is empty * @throws IllegalStateException if stream contains more than one element * @since 1.1.2 */ public T single() { if (iterator.hasNext()) { T singleCandidate = iterator.next(); if (iterator.hasNext()) { throw new IllegalStateException("Stream contains more than one element"); } else { return singleCandidate; } } else { throw new NoSuchElementException("Stream contains no element"); } } /** * Returns the single element wrapped by {@code Optional} class. * If stream is empty, returns {@code Optional.empty()}. * If stream contains more than one element, throws {@code IllegalStateException}. * * <p>This is a short-circuiting terminal operation. * * <p>Example: * <pre> * stream: [] * result: Optional.empty() * * stream: [1] * result: Optional.of(1) * * stream: [1, 2, 3] * result: IllegalStateException * </pre> * * @return an {@code Optional} with single element or {@code Optional.empty()} if stream is empty * @throws IllegalStateException if stream contains more than one element * @since 1.1.2 */ public Optional<T> findSingle() { if (iterator.hasNext()) { T singleCandidate = iterator.next(); if (iterator.hasNext()) { throw new IllegalStateException("Stream contains more than one element"); } else { return Optional.of(singleCandidate); } } else { return Optional.empty(); } } /** * Adds close handler to the current stream. * * <p>This is an intermediate operation. * * @param closeHandler an action to execute when the stream is closed * @return the new stream with the close handler * @since 1.1.8 */ public Stream<T> onClose(final Runnable closeHandler) { Objects.requireNonNull(closeHandler); final Params newParams; if (params == null) { newParams = new Params(); newParams.closeHandler = closeHandler; } else { newParams = params; final Runnable firstHandler = newParams.closeHandler; newParams.closeHandler = Compose.runnables(firstHandler, closeHandler); } return new Stream<T>(newParams, iterator); } /** * Causes close handler to be invoked if it exists. * Since most of the stream providers are lists or arrays, * it is not necessary to close the stream. * * @since 1.1.8 */ @Override public void close() { if (params != null && params.closeHandler != null) { params.closeHandler.run(); params.closeHandler = null; } } private static final int MATCH_ANY = 0; private static final int MATCH_ALL = 1; private static final int MATCH_NONE = 2; private boolean match(Predicate<? super T> predicate, int matchKind) { final boolean kindAny = (matchKind == MATCH_ANY); final boolean kindAll = (matchKind == MATCH_ALL); while (iterator.hasNext()) { final T value = iterator.next(); /*if (predicate.test(value)) { // anyMatch -> true // noneMatch -> false if (!kindAll) { return matchAny; } } else { // allMatch -> false if (kindAll) { return false; } }*/ // match && !kindAll -> kindAny // !match && kindAll -> false final boolean match = predicate.test(value); if (match ^ kindAll) { return kindAny && match; // (match ? kindAny : false); } } // anyMatch -> false // allMatch -> true // noneMatch -> true return !kindAny; } //</editor-fold> }