All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.annimon.stream.Stream Maven / Gradle / Ivy

package com.annimon.stream;

import java.io.Closeable;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.annimon.stream.internal.Compose;
import com.annimon.stream.internal.Operators;
import com.annimon.stream.internal.Params;
import com.annimon.stream.iterator.LazyIterator;
import com.annimon.stream.operator.ObjArray;
import com.annimon.stream.operator.ObjChunkBy;
import com.annimon.stream.operator.ObjConcat;
import com.annimon.stream.operator.ObjDistinct;
import com.annimon.stream.operator.ObjDistinctBy;
import com.annimon.stream.operator.ObjDropWhile;
import com.annimon.stream.operator.ObjFilter;
import com.annimon.stream.operator.ObjFlatMap;
import com.annimon.stream.operator.ObjFlatMapToDouble;
import com.annimon.stream.operator.ObjFlatMapToInt;
import com.annimon.stream.operator.ObjFlatMapToLong;
import com.annimon.stream.operator.ObjGenerate;
import com.annimon.stream.operator.ObjIterate;
import com.annimon.stream.operator.ObjLimit;
import com.annimon.stream.operator.ObjMap;
import com.annimon.stream.operator.ObjMapToDouble;
import com.annimon.stream.operator.ObjMapToInt;
import com.annimon.stream.operator.ObjMapToLong;
import com.annimon.stream.operator.ObjMerge;
import com.annimon.stream.operator.ObjPeek;
import com.annimon.stream.operator.ObjScan;
import com.annimon.stream.operator.ObjScanIdentity;
import com.annimon.stream.operator.ObjSkip;
import com.annimon.stream.operator.ObjSlidingWindow;
import com.annimon.stream.operator.ObjSorted;
import com.annimon.stream.operator.ObjTakeUntil;
import com.annimon.stream.operator.ObjTakeWhile;
import com.annimon.stream.operator.ObjZip;
import com.landawn.abacus.util.Comparators;
import com.landawn.abacus.util.Fn;
import com.landawn.abacus.util.Indexed;
import com.landawn.abacus.util.N;
import com.landawn.abacus.util.Optional;
import com.landawn.abacus.util.function.BiConsumer;
import com.landawn.abacus.util.function.BiFunction;
import com.landawn.abacus.util.function.BinaryOperator;
import com.landawn.abacus.util.function.Consumer;
import com.landawn.abacus.util.function.Function;
import com.landawn.abacus.util.function.IntFunction;
import com.landawn.abacus.util.function.Predicate;
import com.landawn.abacus.util.function.Supplier;
import com.landawn.abacus.util.function.ToDoubleFunction;
import com.landawn.abacus.util.function.ToIntFunction;
import com.landawn.abacus.util.function.ToLongFunction;
import com.landawn.abacus.util.function.UnaryOperator;
import com.landawn.abacus.util.stream.Collector;
import com.landawn.abacus.util.stream.Collectors;

/**
 * A sequence of elements supporting aggregate operations.
 *
 * @param  the type of the stream elements
 */
public class Stream implements Closeable {
    static final Object NONE = new Object();

    @SuppressWarnings({ "rawtypes" })
    private static final Stream EMPTY = new Stream<>(Collections.emptyList());

    /**
     * Returns an empty stream.
     *
     * @param  the type of the stream elements
     * @return the new empty stream
     */
    @SuppressWarnings("unchecked")
    public static  Stream empty() {
        return EMPTY;
    }

    public static  Stream just(final T value) {
        return of(value);
    }

    /**
     * If specified element is null, returns an empty {@code Stream},
     * otherwise returns a {@code Stream} containing a single element.
     *
     * @param  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
     */
    public static  Stream ofNullable(T element) {
        return (element == null) ? Stream. empty() : Stream.of(element);
    }

    /**
     * Creates a {@code Stream} from the specified values.
     *
     * @param  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
     */
    @SafeVarargs
    public static  Stream of(final T... elements) {
        if (elements == null || elements.length == 0) {
            return Stream. empty();
        }

        return new Stream<>(new ObjArray<>(elements));
    }

    /**
     * Creates a {@code Stream} from {@code Map} entries.
     *
     * @param  the type of map keys
     * @param  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  Stream of(Collection c) {
        if (c == null || c.size() == 0) {
            return Stream. empty();
        }

        return new Stream<>(c);
    }

    /**
     * Creates a {@code Stream} from {@code Map} entries.
     *
     * @param  the type of map keys
     * @param  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  Stream> of(Map map) {
        if (map == null || map.size() == 0) {
            return Stream.> empty();
        }

        return new Stream<>(map.entrySet());
    }

    /**
     * Creates a {@code Stream} from any class that implements {@code Iterator} interface.
     *
     * @param  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  Stream of(Iterator iterator) {
        N.requireNonNull(iterator);
        return new Stream<>(iterator);
    }

    /**
     * Creates a {@code Stream} by elements that generated by {@code Supplier}.
     *
     * @param  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  Stream generate(final Supplier supplier) {
        N.requireNonNull(supplier);
        return new Stream<>(new ObjGenerate<>(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.
     *
     * 

Example: *

     * seed: 1
     * op: (a) -> a + 5
     * result: [1, 6, 11, 16, ...]
     * 
* * @param 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 Stream iterate(final T seed, final UnaryOperator op) { N.requireNonNull(op); return new Stream<>(new ObjIterate<>(seed, op)); } /** * Creates a {@code Stream} by iterative application {@code UnaryOperator} function * to an initial element {@code seed}, conditioned on satisfying the supplied predicate. * *

Example: *

     * seed: 0
     * predicate: (a) -> a < 20
     * op: (a) -> a + 5
     * result: [0, 5, 10, 15]
     * 
* * @param 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 Stream iterate(final T seed, final Predicate predicate, final UnaryOperator op) { N.requireNonNull(predicate); return iterate(seed, op).takeWhile(predicate); } /** * Concatenates two streams. * *

Example: *

     * stream 1: [1, 2, 3, 4]
     * stream 2: [5, 6]
     * result:   [1, 2, 3, 4, 5, 6]
     * 
* * @param 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 Stream concat(final Stream stream1, final Stream stream2) { N.requireNonNull(stream1); N.requireNonNull(stream2); @SuppressWarnings("resource") Stream result = new Stream<>(new ObjConcat<>(stream1.iterator, stream2.iterator)); return result.onClose(Compose.closeables(stream1, stream2)); } /** * Concatenates two iterators to a stream. * *

Example: *

     * iterator 1: [1, 2, 3, 4]
     * iterator 2: [5, 6]
     * result:     [1, 2, 3, 4, 5, 6]
     * 
* * @param The type of iterator elements * @param iterator1 the first iterator * @param iterator2 the second iterator * @return the new stream * @throws NullPointerException if {@code iterator1} or {@code iterator2} is null * @since 1.1.9 */ public static Stream concat(final Iterator iterator1, final Iterator iterator2) { N.requireNonNull(iterator1); N.requireNonNull(iterator2); return new Stream<>(new ObjConcat<>(iterator1, iterator2)); } public static Stream concat(final Collection c1, final Collection c2) { return concat(c1 == null ? Collections. emptyIterator() : c1.iterator(), c2 == null ? Collections. emptyIterator() : c2.iterator()); } public static Stream concat(final T[] a, final T[] b) { return concat(a == null ? Collections. emptyIterator() : Arrays.asList(a).iterator(), b == null ? Collections. emptyIterator() : Arrays.asList(b).iterator()); } /** * Combines two streams by applying specified combiner function to each element at same position. * *

Example: *

     * combiner: (a, b) -> a + b
     * stream 1: [1, 2, 3, 4]
     * stream 2: [5, 6, 7, 8]
     * result:   [6, 8, 10, 12]
     * 
* * @param the type of first stream elements * @param the type of second stream elements * @param 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 Stream zip(final Stream stream1, final Stream stream2, final BiFunction combiner) { N.requireNonNull(stream1); N.requireNonNull(stream2); return Stream. zip(stream1.iterator, stream2.iterator, combiner); } /** * Combines two iterators to a stream by applying specified combiner function to each element at same position. * *

Example: *

     * combiner: (a, b) -> a + b
     * stream 1: [1, 2, 3, 4]
     * stream 2: [5, 6, 7, 8]
     * result:   [6, 8, 10, 12]
     * 
* * @param the type of first iterator elements * @param the type of second iterator elements * @param 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 Stream zip(final Iterator iterator1, final Iterator iterator2, final BiFunction combiner) { N.requireNonNull(iterator1); N.requireNonNull(iterator2); return new Stream<>(new ObjZip<>(iterator1, iterator2, combiner)); } public static Stream zip(final Collection c1, final Collection c2, final BiFunction combiner) { return zip(c1 == null ? Collections. emptyIterator() : c1.iterator(), c2 == null ? Collections. emptyIterator() : c2.iterator(), combiner); } public static Stream zip(final F[] a, final S[] b, final BiFunction combiner) { return zip(a == null ? Collections. emptyIterator() : Arrays.asList(a).iterator(), b == null ? Collections. emptyIterator() : Arrays.asList(b).iterator(), combiner); } /** * Merges elements of two streams according to the supplied selector function. * *

Example 1 — Merge two sorted streams: *

     * stream1: [1, 3, 8, 10]
     * stream2: [2, 5, 6, 12]
     * selector: (a, b) -> a < b ? TAKE_FIRST : TAKE_SECOND
     * result: [1, 2, 3, 5, 6, 8, 10, 12]
     * 
* *

Example 2 — Concat two streams: *

     * stream1: [0, 3, 1]
     * stream2: [2, 5, 6, 1]
     * selector: (a, b) -> TAKE_SECOND
     * result: [2, 5, 6, 1, 0, 3, 1]
     * 
* * @param the type of the elements * @param stream1 the first stream * @param stream2 the second stream * @param selector the selector function used to choose elements * @return the new stream * @throws NullPointerException if {@code stream1} or {@code stream2} is null * @since 1.1.9 */ public static Stream merge(final Stream stream1, final Stream stream2, final BiFunction selector) { N.requireNonNull(stream1); N.requireNonNull(stream2); return Stream. merge(stream1.iterator, stream2.iterator, selector); } /** * Merges elements of two iterators according to the supplied selector function. * *

Example 1 — Merge two sorted iterators: *

     * iterator1: [1, 3, 8, 10]
     * iterator2: [2, 5, 6, 12]
     * selector: (a, b) -> a < b ? TAKE_FIRST : TAKE_SECOND
     * result: [1, 2, 3, 5, 6, 8, 10, 12]
     * 
* *

Example 2 — Concat two iterators: *

     * iterator1: [0, 3, 1]
     * iterator2: [2, 5, 6, 1]
     * selector: (a, b) -> TAKE_SECOND
     * result: [2, 5, 6, 1, 0, 3, 1]
     * 
* * @param the type of the elements * @param iterator1 the first iterator * @param iterator2 the second iterator * @param selector the selector function used to choose elements * @return the new stream * @throws NullPointerException if {@code iterator1} or {@code iterator2} is null * @since 1.1.9 */ public static Stream merge(final Iterator iterator1, final Iterator iterator2, final BiFunction selector) { N.requireNonNull(iterator1); N.requireNonNull(iterator2); return new Stream<>(new ObjMerge<>(iterator1, iterator2, selector)); } public static Stream merge(final Collection c1, final Collection c2, final BiFunction selector) { return merge(c1 == null ? Collections. emptyIterator() : c1.iterator(), c2 == null ? Collections. emptyIterator() : c2.iterator(), selector); } public static Stream merge(final T[] a, final T[] b, final BiFunction selector) { return merge(a == null ? Collections. emptyIterator() : Arrays.asList(a).iterator(), b == null ? Collections. emptyIterator() : Arrays.asList(b).iterator(), selector); } // private final Iterator iterator; private final Params params; private Stream(Iterator iterator) { this(null, iterator); } private Stream(Iterable iterable) { this(null, new LazyIterator<>(iterable)); } private Stream(Params params, Iterable iterable) { this(params, new LazyIterator<>(iterable)); } @SuppressWarnings("unchecked") Stream(Params params, Iterator iterator) { this.params = params; this.iterator = (Iterator) iterator; } /** * Returns internal stream iterator. * * @return internal stream iterator */ public Iterator iterator() { return iterator; } /** * Returns {@code Stream} with elements that satisfy the given predicate. * *

This is an intermediate operation. * *

Example: *

     * predicate: (a) -> a > 2
     * stream: [1, 2, 3, 4, -8, 0, 11]
     * result: [3, 4, 11]
     * 
* * @param predicate the predicate used to filter elements * @return the new stream */ public Stream filter(final Predicate predicate) { return new Stream<>(params, new ObjFilter<>(iterator, predicate)); } /** * Returns {@code Stream} without null elements. * *

This is an intermediate operation. * * @return the new stream * @since 1.1.6 */ public Stream skipNull() { return filter(Fn.notNull()); } /** * Returns {@code Stream} with elements that obtained by applying the given function. * *

This is an intermediate operation. * *

Example: *

     * mapper: (a) -> a + 5
     * stream: [1, 2, 3, 4]
     * result: [6, 7, 8, 9]
     * 
* * @param the type of elements in resulting stream * @param mapper the mapper function used to apply to each element * @return the new stream */ public Stream map(final Function mapper) { return new Stream<>(params, new ObjMap<>(iterator, mapper)); } /** * Returns {@code IntStream} with elements that obtained by applying the given function. * *

This is an intermediate operation. * * @param mapper the mapper function used to apply to each element * @return the new {@code IntStream} * @see #map(com.landawn.abacus.util.function.Function) */ public IntStream mapToInt(final ToIntFunction mapper) { return new IntStream(params, new ObjMapToInt<>(iterator, mapper)); } /** * Returns {@code LongStream} with elements that obtained by applying the given function. * *

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.landawn.abacus.util.function.Function) */ public LongStream mapToLong(final ToLongFunction mapper) { return new LongStream(params, new ObjMapToLong<>(iterator, mapper)); } /** * Returns {@code DoubleStream} with elements that obtained by applying the given function. * *

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.landawn.abacus.util.function.Function) */ public DoubleStream mapToDouble(final ToDoubleFunction mapper) { return new DoubleStream(params, new ObjMapToDouble<>(iterator, mapper)); } @SuppressWarnings("unchecked") public EntryStream mapToEntry(Function> mapper) { final Function identityMapper = Fn.identity(); if (mapper == identityMapper) { return new EntryStream<>((Stream>) this); } else { return new EntryStream<>(this.map(mapper)); } } public EntryStream mapToEntry(final Function keyMapper, final Function valueMapper) { return new EntryStream<>(this.map(new Function>() { @Override public Entry apply(T t) { return new AbstractMap.SimpleImmutableEntry<>(keyMapper.apply(t), valueMapper.apply(t)); } })); } /** * 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. * *

This is an intermediate operation. * *

Example: *

     * mapper: (a) -> [a, a + 5]
     * stream: [1, 2, 3, 4]
     * result: [1, 6, 2, 7, 3, 8, 4, 9]
     * 
* * @param the type of elements in resulting stream * @param mapper the mapper function used to apply to each element * @return the new stream */ public Stream flatMap(final Function> mapper) { return new Stream<>(params, new ObjFlatMap<>(iterator, mapper)); } public Stream flatCollection(final Function> mapper) { return flatMap(new Function>() { @Override public Stream apply(T t) { final Collection c = mapper.apply(t); return c == null || c.size() == 0 ? Stream. empty() : Stream.of(c); } }); } public Stream flatArray(final Function mapper) { return flatMap(new Function>() { @Override public Stream apply(T t) { final R[] a = mapper.apply(t); return a == null || a.length == 0 ? Stream. empty() : Stream.of(a); } }); } /** * 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. * *

This is an intermediate operation. * * @param mapper the mapper function used to apply to each element * @return the new {@code IntStream} * @see #flatMap(com.landawn.abacus.util.function.Function) */ public IntStream flatMapToInt(final Function mapper) { return new IntStream(params, new ObjFlatMapToInt<>(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. * *

This is an intermediate operation. * * @param mapper the mapper function used to apply to each element * @return the new {@code LongStream} * @see #flatMap(com.landawn.abacus.util.function.Function) */ public LongStream flatMapToLong(final Function mapper) { return new LongStream(params, new ObjFlatMapToLong<>(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. * *

This is an intermediate operation. * * @param mapper the mapper function used to apply to each element * @return the new {@code DoubleStream} * @see #flatMap(com.landawn.abacus.util.function.Function) */ public DoubleStream flatMapToDouble(final Function mapper) { return new DoubleStream(params, new ObjFlatMapToDouble<>(iterator, mapper)); } public EntryStream flatMapToEntry(Function>> mapper) { return EntryStream.of(flatMap(mapper)); } // public EntryStream flatMapToEntry2(final Function> mapper) { // final Function>> mapper2 = new Function>>() { // @Override // public Stream> apply(T t) { // return Stream.of(mapper.apply(t)); // } // }; // // return EntryStream.of(flatMap(mapper2)); // } /** * Returns {@code Stream} with indexed elements. * Indexing starts from 0 with step 1. * *

This is an intermediate operation. * *

Example: *

     * stream: ["a", "b", "c"]
     * result: [(0, "a"), (1, "b"), (2, "c")]
     * 
* * @return the new {@code IntPair} stream * @since 1.1.2 */ public Stream> indexed() { return map(new Function>() { private int index = 0; @Override public Indexed apply(T t) { return Indexed.of(t, index++); } }); } /** * Returns {@code Stream} with distinct elements (as determined by {@code hashCode} and {@code equals} methods). * *

This is a stateful intermediate operation. * *

Example: *

     * stream: [1, 4, 2, 3, 3, 4, 1]
     * result: [1, 4, 2, 3]
     * 
* * @return the new stream */ public Stream distinct() { return new Stream<>(params, new ObjDistinct<>(iterator)); } /** * Returns {@code Stream} with distinct elements (as determined by {@code hashCode} * and {@code equals} methods) according to the given classifier function. * *

This is a stateful intermediate operation. * *

Example: *

     * classifier: (str) -> str.length()
     * stream: ["a", "bc", "d", "ef", "ghij"]
     * result: ["a", "bc", "ghij"]
     * 
* * @param keyExtractor the classifier function * @return the new stream * @since 1.1.8 */ public Stream distinctBy(Function keyExtractor) { return new Stream<>(params, new ObjDistinctBy<>(iterator, keyExtractor)); } /** * Returns {@code Stream} with sorted elements (as determinated by {@link Comparable} interface). * *

This is a stateful intermediate operation. *

If the elements of this stream are not {@link Comparable}, * a {@code java.lang.ClassCastException} may be thrown when the terminal operation is executed. * *

Example: *

     * stream: [3, 4, 1, 2]
     * result: [1, 2, 3, 4]
     * 
* * @return the new stream */ public Stream sorted() { return sorted(new Comparator() { @SuppressWarnings({ "unchecked", "rawtypes" }) @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}). * *

This is a stateful intermediate operation. * *

Example: *

     * comparator: (a, b) -> -a.compareTo(b)
     * stream: [1, 2, 3, 4]
     * result: [4, 3, 2, 1]
     * 
* * @param comparator the {@code Comparator} to compare elements * @return the new stream */ public Stream sorted(final Comparator comparator) { return new Stream<>(params, new ObjSorted<>(iterator, comparator)); } /** * Returns {@code Stream} with sorted elements (as determinated by {@code Comparable} interface). * Each element transformed by given function {@code f} before comparing. * *

This is a stateful intermediate operation. * *

Example: *

     * f: (a) -> -a
     * stream: [1, 2, 3, 4]
     * result: [4, 3, 2, 1]
     * 
* * @param the type of the result of transforming function * @param keyExtractor the transformation function * @return the new stream */ public > Stream sortedBy(final Function keyExtractor) { return sorted(Comparators.comparingBy(keyExtractor)); } /** * Partitions {@code Stream} into {@code Map} entries according to the given classifier function. * *

This is a stateful intermediate operation. * *

Example: *

     * classifier: (str) -> str.length()
     * stream: ["a", "bc", "d", "ef", "ghij"]
     * result: [{1: ["a", "d"]}, {2: ["bc", "ef"]}, {4: ["ghij"]}]
     * 
* * @param the type of the keys, which are result of the classifier function * @param classifier the classifier function * @return the new stream */ public Stream>> groupBy(final Function classifier) { final Map> map = collect(Collectors. groupingBy(classifier)); return new Stream<>(params, map.entrySet()); } public Stream> groupBy(Function classifier, Collector downstream) { final Map map = collect(Collectors.groupingBy(classifier, downstream)); return new Stream<>(params, map.entrySet()); } public Stream> groupBy(final Function classifier, final Collector downstream, final Supplier> mapFactory) { final Map map = collect(Collectors.groupingBy(classifier, downstream, mapFactory)); return new Stream<>(params, map.entrySet()); } public EntryStream> groupByToEntry(final Function classifier) { final Function>, Map.Entry>> mapper = Fn.identity(); @SuppressWarnings("unchecked") final Function classifier2 = (Function) classifier; return groupBy(classifier2).mapToEntry(mapper); } public EntryStream groupByToEntry(Function classifier, Collector downstream) { final Function, Map.Entry> mapper = Fn.identity(); @SuppressWarnings("unchecked") final Function classifier2 = (Function) classifier; return groupBy(classifier2, downstream).mapToEntry(mapper); } public EntryStream groupByToEntry(final Function classifier, final Collector downstream, final Supplier> mapFactory) { final Function, Map.Entry> mapper = Fn.identity(); @SuppressWarnings("unchecked") final Function classifier2 = (Function) classifier; return groupBy(classifier2, downstream, mapFactory).mapToEntry(mapper); } public Map> groupTo(final Function classifier) { return collect(Collectors. groupingBy(classifier)); } public Map groupTo(Function classifier, Collector downstream) { return collect(Collectors.groupingBy(classifier, downstream)); } public > M groupTo(final Function classifier, final Collector downstream, final Supplier mapFactory) { return collect(Collectors.groupingBy(classifier, downstream, mapFactory)); } /** * 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. * *

This is an intermediate operation. * *

Example: *

     * 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]]
     * 
* * @param the type of the keys, which are the result of the classifier function * @param classifier the classifier function * @return the new stream */ public Stream> chunkBy(final Function classifier) { return new Stream<>(params, new ObjChunkBy<>(iterator, classifier)); } public Stream> split(final int size) { return sliding(size, size); } /** * 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 #sliding(int, int)} with a {@code stepWidth} of 1. * *

This is an intermediate operation. * *

Example: *

     * windowSize: 3
     * stream: [1, 2, 3, 4, 5]
     * result: [[1, 2, 3], [2, 3, 4], [3, 4, 5]]
     * 
* * @param windowSize number of elements that will be emitted together in a list * @return the new stream * @see #sliding(int, int) */ public Stream> sliding(final int windowSize) { return sliding(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). * *

This is an intermediate operation. * *

Example: *

     * 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]]
     * 
* * @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> sliding(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<>(params, new ObjSlidingWindow<>(iterator, windowSize, stepWidth)); } /** * Performs provided action on each element. * *

This is an intermediate operation. * * @param action the action to be performed on each element * @return the new stream */ public Stream peek(final Consumer action) { return new Stream<>(params, new ObjPeek<>(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. * *

This is an intermediate operation. * *

Example: *

     * accumulator: (a, b) -> a + b
     * stream: [1, 2, 3, 4, 5]
     * result: [1, 3, 6, 10, 15]
     * 
* * @param accumulator the accumulation function * @return the new stream * @throws NullPointerException if {@code accumulator} is null * @since 1.1.6 */ public Stream scan(final BiFunction accumulator) { N.requireNonNull(accumulator); return new Stream<>(params, new ObjScan<>(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. * *

This is an intermediate operation. * *

Example: *

     * identity: 0
     * accumulator: (a, b) -> a + b
     * stream: [1, 2, 3, 4, 5]
     * result: [0, 1, 3, 6, 10, 15]
     * 
* * @param 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 Stream scan(final R identity, final BiFunction accumulator) { N.requireNonNull(accumulator); return new Stream<>(params, new ObjScanIdentity<>(iterator, identity, accumulator)); } /** * Takes elements while the predicate returns {@code true}. * *

This is an intermediate operation. * *

Example: *

     * predicate: (a) -> a < 3
     * stream: [1, 2, 3, 4, 1, 2, 3, 4]
     * result: [1, 2]
     * 
* * @param predicate the predicate used to take elements * @return the new stream */ public Stream takeWhile(final Predicate predicate) { return new Stream<>(params, new ObjTakeWhile<>(iterator, predicate)); } /** * Takes elements while the predicate returns {@code false}. * Once predicate condition is satisfied by an element, the stream * finishes with this element. * *

This is an intermediate operation. * *

Example: *

     * stopPredicate: (a) -> a > 2
     * stream: [1, 2, 3, 4, 1, 2, 3, 4]
     * result: [1, 2, 3]
     * 
* * @param stopPredicate the predicate used to take elements * @return the new stream * @since 1.1.6 */ public Stream takeUntil(final Predicate stopPredicate) { return new Stream<>(params, new ObjTakeUntil<>(iterator, stopPredicate)); } /** * Drops elements while the predicate is true, then returns the rest. * *

This is an intermediate operation. * *

Example: *

     * predicate: (a) -> a < 3
     * stream: [1, 2, 3, 4, 1, 2, 3, 4]
     * result: [3, 4, 1, 2, 3, 4]
     * 
* * @param predicate the predicate used to drop elements * @return the new stream */ public Stream dropWhile(final Predicate predicate) { return new Stream<>(params, new ObjDropWhile<>(iterator, predicate)); } /** * Returns {@code Stream} with first {@code maxSize} elements. * *

This is a short-circuiting stateful intermediate operation. * *

Example: *

     * maxSize: 3
     * stream: [1, 2, 3, 4, 5]
     * result: [1, 2, 3]
     *
     * maxSize: 10
     * stream: [1, 2]
     * result: [1, 2]
     * 
* * @param maxSize the number of elements to limit * @return the new stream * @throws IllegalArgumentException if {@code maxSize} is negative */ public Stream limit(final long maxSize) { if (maxSize < 0) { throw new IllegalArgumentException("maxSize cannot be negative"); } if (maxSize == 0) { return Stream.empty(); } return new Stream<>(params, new ObjLimit<>(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. * *

This is a stateful intermediate operation. * *

Example: *

     * n: 3
     * stream: [1, 2, 3, 4, 5]
     * result: [4, 5]
     *
     * n: 10
     * stream: [1, 2]
     * result: []
     * 
* * @param n the number of elements to skip * @return the new stream * @throws IllegalArgumentException if {@code n} is negative */ public Stream skip(final long n) { if (n < 0) throw new IllegalArgumentException("n cannot be negative"); if (n == 0) return this; return new Stream<>(params, new ObjSkip<>(iterator, n)); } /** * Tests whether any elements match the given predicate. * *

This is a short-circuiting terminal operation. * *

Example: *

     * predicate: (a) -> a == 5
     * stream: [1, 2, 3, 4, 5]
     * result: true
     *
     * predicate: (a) -> a == 5
     * stream: [5, 5, 5]
     * result: true
     * 
* * @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 predicate) { return match(predicate, MATCH_ANY); } /** * Tests whether all elements match the given predicate. * *

This is a short-circuiting terminal operation. * *

Example: *

     * predicate: (a) -> a == 5
     * stream: [1, 2, 3, 4, 5]
     * result: false
     *
     * predicate: (a) -> a == 5
     * stream: [5, 5, 5]
     * result: true
     * 
* * @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 predicate) { return match(predicate, MATCH_ALL); } /** * Tests whether no elements match the given predicate. * *

This is a short-circuiting terminal operation. * *

Example: *

     * predicate: (a) -> a == 5
     * stream: [1, 2, 3, 4, 5]
     * result: false
     *
     * predicate: (a) -> a == 5
     * stream: [1, 2, 3]
     * result: true
     * 
* * @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 predicate) { return match(predicate, MATCH_NONE); } /** * Returns the first element wrapped by {@code Optional} class. * If stream is empty, returns {@code Optional.empty()}. * *

This is a short-circuiting terminal operation. * * @return an {@code Optional} with the first element * or {@code Optional.empty()} if stream is empty */ public Optional findFirst() { if (iterator.hasNext()) { return Optional. of(iterator.next()); } return Optional.empty(); } /** * Returns the last element wrapped by {@code Optional} class. * If stream is empty, returns {@code Optional.empty()}. * *

This is a short-circuiting terminal operation. * * @return an {@code Optional} with the last element * or {@code Optional.empty()} if the stream is empty * @since 1.1.8 */ public Optional findLast() { return reduce(new BinaryOperator() { @Override public T apply(T left, T right) { return right; } }); } /** * Finds the minimum element according to the given comparator. * *

This is a terminal operation. * *

Example: *

     * comparator: (a, b) -> a.compareTo(b)
     * stream: [1, 2, 3, 4, 5]
     * result: 1
     * 
* * @param comparator the {@code Comparator} to compare elements * @return the minimum element */ public Optional min(Comparator comparator) { return reduce(minBy(comparator)); } public > Optional minBy(final Function keyExtractor) { return min(Comparators.comparingBy(keyExtractor)); } /** * Finds the maximum element according to the given comparator. * *

This is a terminal operation. * *

Example: *

     * comparator: (a, b) -> a.compareTo(b)
     * stream: [1, 2, 3, 4, 5]
     * result: 5
     * 
* * @param comparator the {@code Comparator} to compare elements * @return the maximum element */ public Optional max(Comparator comparator) { return reduce(maxBy(comparator)); } public > Optional maxBy(final Function keyExtractor) { return max(Comparators.comparingBy(keyExtractor)); } /** * Performs the given action on each element. * *

This is a terminal operation. * * @param action the action to be performed on each element */ public void forEach(final Consumer action) { while (iterator.hasNext()) { action.accept(iterator.next()); } } /** * Reduces the elements using provided identity value and the associative accumulation function. * *

This is a terminal operation. * *

Example: *

     * identity: 0
     * accumulator: (a, b) -> a + b
     * stream: [1, 2, 3, 4, 5]
     * result: 15
     * 
* * @param the type of the result * @param identity the initial value * @param accumulator the accumulation function * @return the result of the reduction */ public R reduce(R identity, BiFunction accumulator) { R result = identity; while (iterator.hasNext()) { final T value = iterator.next(); result = accumulator.apply(result, value); } return result; } /** * Reduces the elements using provided associative accumulation function. * *

This is a terminal operation. * * @param accumulator the accumulation function * @return the result of the reduction * @see #reduce(java.lang.Object, com.landawn.abacus.util.function.BiFunction) */ public Optional reduce(BiFunction 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. empty(); } /** * Collects elements to {@code supplier} provided container by applying the given accumulation function. * *

This is a terminal operation. * * @param 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 collect(Supplier supplier, BiConsumer 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. * *

This is a terminal operation. * * @param the type of result * @param the intermediate used by {@code Collector} * @param collector the {@code Collector} * @return the result of collect elements * @see #collect(com.landawn.abacus.util.function.Supplier, com.landawn.abacus.util.function.BiConsumer) */ @SuppressWarnings("unchecked") public R collect(Collector 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 ((Function) castIdentity()).apply(container); } /** * Returns the count of elements in this stream. * *

This is a terminal operation. * * @return the count of elements */ public int count() { int count = 0; while (iterator.hasNext()) { iterator.next(); count++; } return count; } /** * Collects elements to an array. * *

This is a terminal operation. * * @return the result of collect elements * @see #toArray(com.landawn.abacus.util.function.IntFunction) */ public Object[] toArray() { return toArray(new IntFunction() { @Override public Object[] apply(int value) { return new Object[value]; } }); } /** * Collects elements to an array, the {@code generator} constructor of provided. * *

This is a terminal operation. * * @param 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[] toArray(IntFunction generator) { return Operators.toArray(iterator, generator); } /** * Collects elements to a new {@code List}. * *

This implementation does not call {@code collect(Collectors.toList())}, so * it can be faster by reducing method calls. * *

This is a terminal operation. * * @return a new {@code List} * @since 1.1.5 * @see Collectors#toList() */ public List toList() { final List result = new ArrayList<>(); while (iterator.hasNext()) { result.add(iterator.next()); } return result; } public Set toSet() { final Set result = new HashSet<>(); while (iterator.hasNext()) { result.add(iterator.next()); } return result; } public > C toCollection(Supplier supplier) { final C result = supplier.get(); while (iterator.hasNext()) { result.add(iterator.next()); } return result; } /** * * @param keyMapper * @return * @see Collectors#toMap(Function) */ public Map toMap(final Function keyMapper) { final Function valueMapper = Fn.identity(); return collect(Collectors.toMap(keyMapper, valueMapper)); } /** * * @param keyMapper * @param valueMapper * @return * @see Collectors#toMap(Function, Function) */ public Map toMap(final Function keyMapper, final Function valueMapper) { return collect(Collectors.toMap(keyMapper, valueMapper)); } /** * * @param keyMapper * @param valueMapper * @param mergeFunction * @return * @see Collectors#toMap(Function, Function, BinaryOperator) */ public Map toMap(final Function keyMapper, final Function valueMapper, final BinaryOperator mergeFunction) { return collect(Collectors.toMap(keyMapper, valueMapper, mergeFunction)); } /** * * @param keyMapper * @param valueMapper * @param mapFactory * @return * @see Collectors#toMap(Function, Function, Supplier) */ public > M toMap(final Function keyMapper, final Function valueMapper, final Supplier mapFactory) { return collect(Collectors.toMap(keyMapper, valueMapper, mapFactory)); } /** * * @param keyMapper * @param valueMapper * @param mergeFunction * @param mapFactory * @return * @see Collectors#toMap(Function, Function, BinaryOperator, Supplier) */ public > M toMap(Function keyMapper, Function valueMapper, BinaryOperator mergeFunction, Supplier mapFactory) { return collect(Collectors.toMap(keyMapper, valueMapper, mergeFunction, mapFactory)); } /** * Applies custom operator on stream. * * Transforming function can return {@code Stream} for intermediate operations, * or any value for terminal operation. * *

Operator examples: *


     *     // 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;
     *                 }
     *             });
     *         }
     *     }
     * 
* * @param 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 __(Function, R> transfer) { return transfer.apply(this); } /** * Returns a stream consisting of the elements of this stream which are * instances of given class. * *

This is an intermediate operation. * * @param 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 Stream select(final Class clazz) { return (Stream) filter(new Predicate() { @Override public boolean test(T value) { return clazz.isInstance(value); } }); } public void println() { System.out.println(toList()); } /** * Adds close handler to the current stream. * *

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 onClose(final Runnable closeHandler) { N.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<>(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; } } @SuppressWarnings("unchecked") static Function castIdentity() { return new Function() { @Override public R apply(A value) { return (R) value; } }; } /** * Returns a {@code BinaryOperator} which returns lesser of two elements * according to the specified {@code Comparator}. * * @param the type of the input arguments of the comparator * @param comparator a {@code Comparator} for comparing the two values * @return a {@code BinaryOperator} which returns the lesser of its operands, * according to the supplied {@code Comparator} * @throws NullPointerException if the argument is null */ static BinaryOperator minBy(final Comparator comparator) { N.requireNonNull(comparator); return new BinaryOperator() { @Override public T apply(T a, T b) { return comparator.compare(a, b) <= 0 ? a : b; } }; } /** * Returns a {@code BinaryOperator} which returns greater of two elements * according to the specified {@code Comparator}. * * @param the type of the input arguments of the comparator * @param comparator a {@code Comparator} for comparing the two values * @return a {@code BinaryOperator} which returns the greater of its operands, * according to the supplied {@code Comparator} * @throws NullPointerException if the argument is null */ static BinaryOperator maxBy(final Comparator comparator) { N.requireNonNull(comparator); return new BinaryOperator() { @Override public T apply(T a, T b) { return comparator.compare(a, b) >= 0 ? a : b; } }; } 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 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; } // }