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

com.landawn.abacus.util.ExceptionalStream Maven / Gradle / Ivy

Go to download

A general programming library in Java/Android. It's easy to learn and simple to use with concise and powerful APIs.

There is a newer version: 2.1.12
Show newest version
/*
 * Copyright (C) 2019 HaiYang Li
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */

package com.landawn.abacus.util;

import java.io.BufferedReader;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.security.SecureRandom;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Deque;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Queue;
import java.util.Random;
import java.util.Set;

import com.landawn.abacus.DataSet;
import com.landawn.abacus.annotation.Beta;
import com.landawn.abacus.annotation.IntermediateOp;
import com.landawn.abacus.annotation.LazyEvaluation;
import com.landawn.abacus.annotation.SequentialOnly;
import com.landawn.abacus.annotation.TerminalOp;
import com.landawn.abacus.annotation.TerminalOpTriggered;
import com.landawn.abacus.exception.DuplicatedResultException;
import com.landawn.abacus.logging.Logger;
import com.landawn.abacus.logging.LoggerFactory;
import com.landawn.abacus.util.Fn.Factory;
import com.landawn.abacus.util.Fn.Fnn;
import com.landawn.abacus.util.Fn.Suppliers;
import com.landawn.abacus.util.If.OrElse;
import com.landawn.abacus.util.StringUtil.Strings;
import com.landawn.abacus.util.u.Holder;
import com.landawn.abacus.util.u.Optional;
import com.landawn.abacus.util.u.OptionalDouble;
import com.landawn.abacus.util.u.OptionalLong;
import com.landawn.abacus.util.function.BiConsumer;
import com.landawn.abacus.util.function.BinaryOperator;
import com.landawn.abacus.util.function.Function;
import com.landawn.abacus.util.function.IntFunction;
import com.landawn.abacus.util.function.Supplier;
import com.landawn.abacus.util.stream.Collector;
import com.landawn.abacus.util.stream.Collectors;

/**
 * The Stream will be automatically closed after execution(A terminal method is executed/triggered).
 *
 * @author Haiyang Li
 * @param 
 * @param 
 * @since 1.3
 */
@LazyEvaluation
@SequentialOnly
public class ExceptionalStream implements Closeable {

    static final Logger logger = LoggerFactory.getLogger(ExceptionalStream.class);

    static final Random RAND = new SecureRandom();

    static final Throwables.Function, Object>, Object, Exception> KK = new Throwables.Function, Object>, Object, Exception>() {
        @Override
        public Object apply(Map.Entry, Object> t) throws Exception {
            return t.getKey().val();
        }
    };

    private final ExceptionalIterator elements;

    private final boolean sorted;

    private final Comparator comparator;

    private final Deque> closeHandlers;

    private boolean isClosed = false;

    ExceptionalStream(final ExceptionalIterator iter) {
        this(iter, false, null, null);
    }

    ExceptionalStream(final ExceptionalIterator iter, final Deque> closeHandlers) {
        this(iter, false, null, closeHandlers);
    }

    ExceptionalStream(final ExceptionalIterator iter, final boolean sorted, final Comparator comparator,
            final Deque> closeHandlers) {
        this.elements = iter;
        this.sorted = sorted;
        this.comparator = comparator;
        this.closeHandlers = closeHandlers;
    }

    /**
     *
     * @param 
     * @param 
     * @return
     */
    public static  ExceptionalStream empty() {
        return new ExceptionalStream<>(ExceptionalIterator.EMPTY);
    }

    /**
     *
     * @param 
     * @param 
     * @param e
     * @return
     */
    public static  ExceptionalStream just(final T e) {
        return of(e);
    }

    /**
     *
     * @param 
     * @param 
     * @param e
     * @param exceptionType
     * @return
     */
    public static  ExceptionalStream just(final T e, final Class exceptionType) {
        return of(e);
    }

    /**
     * Returns an empty {@code Stream} if the specified {@code t} is null.
     *
     * @param 
     * @param 
     * @param e
     * @return
     */
    public static  ExceptionalStream ofNullable(final T e) {
        if (e == null) {
            return empty();
        }

        return of(e);
    }

    /**
     *
     * @param 
     * @param 
     * @param a
     * @return
     */
    public static  ExceptionalStream of(final T... a) {
        if (N.isNullOrEmpty(a)) {
            return empty();
        }

        final int len = N.len(a);

        return newStream(new ExceptionalIterator() {
            private int position = 0;

            @Override
            public boolean hasNext() throws E {
                return position < len;
            }

            @Override
            public T next() throws E {
                if (position >= len) {
                    throw new NoSuchElementException();
                }

                return a[position++];
            }

            @Override
            public long count() throws E {
                return len - position;
            }

            @Override
            public void skip(long n) throws E {
                N.checkArgNotNegative(n, "n");

                if (n > len - position) {
                    position = len;
                } else {
                    position += n;
                }
            }
        });
    }

    /**
     *
     * @param 
     * @param 
     * @param c
     * @return
     */
    public static  ExceptionalStream of(final Collection c) {
        if (N.isNullOrEmpty(c)) {
            return empty();
        }

        @SuppressWarnings("deprecation")
        final T[] a = (T[]) InternalUtil.getInternalArray(c);

        if (a != null) {
            final int len = c.size();

            return newStream(new ExceptionalIterator() {
                private int position = 0;

                @Override
                public boolean hasNext() throws E {
                    return position < len;
                }

                @Override
                public T next() throws E {
                    if (position >= len) {
                        throw new NoSuchElementException();
                    }

                    return a[position++];
                }

                @Override
                public long count() throws E {
                    return len - position;
                }

                @Override
                public void skip(long n) throws E {
                    N.checkArgNotNegative(n, "n");

                    if (n > len - position) {
                        position = len;
                    } else {
                        position += n;
                    }
                }
            });
        }

        return of(c.iterator());
    }

    /**
     *
     * @param 
     * @param 
     * @param iter
     * @return
     */
    public static  ExceptionalStream of(final Iterator iter) {
        if (iter == null) {
            return empty();
        }

        return newStream(ExceptionalIterator. wrap(iter));
    }

    /**
     *
     * @param 
     * @param 
     * @param iterable
     * @return
     */
    public static  ExceptionalStream of(final Iterable iterable) {
        if (iterable == null) {
            return empty();
        }

        return of(iterable.iterator());
    }

    /**
     *
     * @param  the key type
     * @param  the value type
     * @param 
     * @param m
     * @return
     */
    public static  ExceptionalStream, E> of(final Map m) {
        if (m == null) {
            return empty();
        }

        return of(m.entrySet());
    }

    /**
     *
     * @param 
     * @param 
     * @param c
     * @param exceptionType
     * @return
     */
    public static  ExceptionalStream of(final Collection c, final Class exceptionType) {
        return of(c);
    }

    /**
     *
     * @param 
     * @param 
     * @param iter
     * @param exceptionType
     * @return
     */
    public static  ExceptionalStream of(final Iterator iter, final Class exceptionType) {
        return of(iter);
    }

    /**
     *
     * @param 
     * @param 
     * @param iterable
     * @param exceptionType
     * @return
     */
    public static  ExceptionalStream of(final Iterable iterable, final Class exceptionType) {
        return of(iterable);
    }

    /**
     *
     * @param  the key type
     * @param  the value type
     * @param 
     * @param m
     * @param exceptionType
     * @return
     */
    public static  ExceptionalStream, E> of(final Map m, final Class exceptionType) {
        return of(m);
    }

    /**
     *
     * @param 
     * @param a
     * @return
     */
    public static  ExceptionalStream of(final int[] a) {
        if (N.isNullOrEmpty(a)) {
            return empty();
        }

        final int len = N.len(a);

        return newStream(new ExceptionalIterator() {
            private int position = 0;

            @Override
            public boolean hasNext() throws E {
                return position < len;
            }

            @Override
            public Integer next() throws E {
                return a[position++];
            }

            @Override
            public long count() throws E {
                return len - position;
            }

            @Override
            public void skip(long n) throws E {
                N.checkArgNotNegative(n, "n");

                if (n > len - position) {
                    position = len;
                } else {
                    position += n;
                }
            }
        });
    }

    /**
     *
     * @param 
     * @param a
     * @return
     */
    public static  ExceptionalStream of(final long[] a) {
        if (N.isNullOrEmpty(a)) {
            return empty();
        }

        final int len = N.len(a);

        return newStream(new ExceptionalIterator() {
            private int position = 0;

            @Override
            public boolean hasNext() throws E {
                return position < len;
            }

            @Override
            public Long next() throws E {
                return a[position++];
            }

            @Override
            public long count() throws E {
                return len - position;
            }

            @Override
            public void skip(long n) throws E {
                N.checkArgNotNegative(n, "n");

                if (n > len - position) {
                    position = len;
                } else {
                    position += n;
                }
            }
        });
    }

    /**
     *
     * @param 
     * @param a
     * @return
     */
    public static  ExceptionalStream of(final double[] a) {
        if (N.isNullOrEmpty(a)) {
            return empty();
        }

        final int len = N.len(a);

        return newStream(new ExceptionalIterator() {
            private int position = 0;

            @Override
            public boolean hasNext() throws E {
                return position < len;
            }

            @Override
            public Double next() throws E {
                return a[position++];
            }

            @Override
            public long count() throws E {
                return len - position;
            }

            @Override
            public void skip(long n) throws E {
                N.checkArgNotNegative(n, "n");

                if (n > len - position) {
                    position = len;
                } else {
                    position += n;
                }
            }
        });
    }

    /**
     * Lazy evaluation.
     * 
* * This is equal to: {@code ExceptionalStream.just(supplier).flattMap(it -> it.get())}. * * @param supplier * @return */ @Beta public static ExceptionalStream of(final Throwables.Supplier, ? extends E> supplier) { N.checkArgNotNull(supplier, "supplier"); return ExceptionalStream., ? extends E>, E> just(supplier) .flattMap(new Throwables.Function, ? extends E>, Collection, E>() { @Override public Collection apply(Throwables.Supplier, ? extends E> t) throws E { return t.get(); } }); } /** * Lazy evaluation. *
* * This is equal to: {@code ExceptionalStream.just(supplier).flatMap(it -> it.get())}. * * @param supplier * @return */ public static ExceptionalStream from( final Throwables.Supplier, ? extends E> supplier) { N.checkArgNotNull(supplier, "supplier"); return ExceptionalStream., ? extends E>, E> just(supplier) .flatMap( new Throwables.Function, ? extends E>, ExceptionalStream, E>() { @Override public ExceptionalStream apply( Throwables.Supplier, ? extends E> t) throws E { return t.get(); } }); } public static ExceptionalStream ofKeys(final Map map) { if (N.isNullOrEmpty(map)) { return empty(); } return of(map.keySet()); } public static ExceptionalStream ofValues(final Map map) { if (N.isNullOrEmpty(map)) { return empty(); } return of(map.values()); } /** * * @param * @param * @param hasNext * @param next * @return */ public static ExceptionalStream iterate(final Throwables.BooleanSupplier hasNext, final Throwables.Supplier next) { N.checkArgNotNull(hasNext, "hasNext"); N.checkArgNotNull(next, "next"); return newStream(new ExceptionalIterator() { private boolean hasNextVal = false; @Override public boolean hasNext() throws E { if (hasNextVal == false) { hasNextVal = hasNext.getAsBoolean(); } return hasNextVal; } @Override public T next() throws E { if (hasNextVal == false && hasNext() == false) { throw new NoSuchElementException(); } hasNextVal = false; return next.get(); } }); } /** * * @param * @param * @param init * @param hasNext * @param f * @return */ public static ExceptionalStream iterate(final T init, final Throwables.BooleanSupplier hasNext, final Throwables.UnaryOperator f) { N.checkArgNotNull(hasNext, "hasNext"); N.checkArgNotNull(f, "f"); return newStream(new ExceptionalIterator() { private final T NONE = (T) N.NULL_MASK; private T t = NONE; private boolean hasNextVal = false; @Override public boolean hasNext() throws E { if (hasNextVal == false) { hasNextVal = hasNext.getAsBoolean(); } return hasNextVal; } @Override public T next() throws E { if (hasNextVal == false && hasNext() == false) { throw new NoSuchElementException(); } hasNextVal = false; return t = (t == NONE) ? init : f.apply(t); } }); } /** * * @param * @param * @param init * @param hasNext * @param f * @return */ public static ExceptionalStream iterate(final T init, final Throwables.Predicate hasNext, final Throwables.UnaryOperator f) { N.checkArgNotNull(hasNext, "hasNext"); N.checkArgNotNull(f, "f"); return newStream(new ExceptionalIterator() { private final T NONE = (T) N.NULL_MASK; private T t = NONE; private T cur = NONE; private boolean hasMore = true; private boolean hasNextVal = false; @Override public boolean hasNext() throws E { if (hasNextVal == false && hasMore) { hasNextVal = hasNext.test((cur = (t == NONE ? init : f.apply(t)))); if (hasNextVal == false) { hasMore = false; } } return hasNextVal; } @Override public T next() throws E { if (hasNextVal == false && hasNext() == false) { throw new NoSuchElementException(); } t = cur; cur = NONE; hasNextVal = false; return t; } }); } /** * * @param * @param * @param init * @param f * @return */ public static ExceptionalStream iterate(final T init, final Throwables.UnaryOperator f) { N.checkArgNotNull(f, "f"); return newStream(new ExceptionalIterator() { private final T NONE = (T) N.NULL_MASK; private T t = NONE; @Override public boolean hasNext() throws E { return true; } @Override public T next() throws E { return t = t == NONE ? init : f.apply(t); } }); } public static ExceptionalStream generate(final Throwables.Supplier supplier) { N.checkArgNotNull(supplier, "supplier"); return newStream(new ExceptionalIterator() { @Override public boolean hasNext() throws E { return true; } @Override public T next() throws E { return supplier.get(); } }); } public static ExceptionalStream repeat(final T element, final long n) { N.checkArgNotNegative(n, "n"); if (n == 0) { return empty(); } return newStream(new ExceptionalIterator() { private long cnt = n; @Override public boolean hasNext() throws E { return cnt > 0; } @Override public T next() throws E { if (cnt-- <= 0) { throw new NoSuchElementException(); } return element; } }); } /** * * @param file * @return */ public static ExceptionalStream lines(final File file) { return lines(file, Charsets.UTF_8); } /** * * @param file * @param charset * @return */ public static ExceptionalStream lines(final File file, final Charset charset) { N.checkArgNotNull(file, "file"); final ExceptionalIterator iter = createLazyLineIterator(file, null, charset, null, true); return newStream(iter).onClose(new Throwables.Runnable() { @Override public void run() throws IOException { iter.close(); } }); } /** * * @param path * @return */ public static ExceptionalStream lines(final Path path) { return lines(path, Charsets.UTF_8); } /** * * @param path * @param charset * @return */ public static ExceptionalStream lines(final Path path, final Charset charset) { N.checkArgNotNull(path, "path"); final ExceptionalIterator iter = createLazyLineIterator(null, path, charset, null, true); return newStream(iter).onClose(new Throwables.Runnable() { @Override public void run() throws IOException { iter.close(); } }); } /** * * @param reader * @return */ public static ExceptionalStream lines(final Reader reader) { N.checkArgNotNull(reader, "reader"); return newStream(createLazyLineIterator(null, null, Charsets.UTF_8, reader, false)); } public static ExceptionalStream listFiles(final File parentPath) { if (!parentPath.exists()) { return empty(); } return of(parentPath.listFiles()); } public static ExceptionalStream listFiles(final File parentPath, final boolean recursively) { if (!parentPath.exists()) { return empty(); } else if (recursively == false) { return of(parentPath.listFiles()); } final ExceptionalIterator iter = new ExceptionalIterator() { private final Queue paths = N.asLinkedList(parentPath); private File[] subFiles = null; private int cursor = 0; @Override public boolean hasNext() { if ((subFiles == null || cursor >= subFiles.length) && paths.size() > 0) { cursor = 0; subFiles = null; while (paths.size() > 0) { subFiles = paths.poll().listFiles(); if (N.notNullOrEmpty(subFiles)) { break; } } } return subFiles != null && cursor < subFiles.length; } @Override public File next() { if (hasNext() == false) { throw new NoSuchElementException(); } if (subFiles[cursor].isDirectory()) { paths.offer(subFiles[cursor]); } return subFiles[cursor++]; } }; return newStream(iter); } /** * Creates the lazy line iterator. * * @param file * @param path * @param charset * @param reader * @param closeReader * @return */ private static ExceptionalIterator createLazyLineIterator(final File file, final Path path, final Charset charset, final Reader reader, final boolean closeReader) { return ExceptionalIterator.of(new Throwables.Supplier, IOException>() { private ExceptionalIterator lazyIter = null; @Override public synchronized ExceptionalIterator get() { if (lazyIter == null) { lazyIter = new ExceptionalIterator() { private BufferedReader bufferedReader; { if (reader != null) { bufferedReader = reader instanceof BufferedReader ? ((BufferedReader) reader) : new BufferedReader(reader); } else if (file != null) { bufferedReader = IOUtil.newBufferedReader(file, charset == null ? Charsets.UTF_8 : charset); } else { bufferedReader = IOUtil.newBufferedReader(path, charset == null ? Charsets.UTF_8 : charset); } } private String cachedLine; private boolean finished = false; @Override public boolean hasNext() throws IOException { if (this.cachedLine != null) { return true; } else if (this.finished) { return false; } else { this.cachedLine = this.bufferedReader.readLine(); if (this.cachedLine == null) { this.finished = true; return false; } else { return true; } } } @Override public String next() throws IOException { if (!this.hasNext()) { throw new NoSuchElementException("No more lines"); } else { String res = this.cachedLine; this.cachedLine = null; return res; } } @Override public void close() throws IOException { if (closeReader) { IOUtil.close(bufferedReader); } } }; } return lazyIter; } }); } @SafeVarargs public static ExceptionalStream concat(final T[]... a) { if (N.isNullOrEmpty(a)) { return empty(); } return of(Iterators.concat(a)); } @SafeVarargs public static ExceptionalStream concat(final Collection... a) { if (N.isNullOrEmpty(a)) { return empty(); } return of(Iterators.concat(a)); } /** * * @param * @param * @param a * @return */ @SafeVarargs public static ExceptionalStream concat(final ExceptionalStream... a) { if (N.isNullOrEmpty(a)) { return empty(); } return concat(Array.asList(a)); } /** * * @param * @param * @param c * @return */ public static ExceptionalStream concat(final Collection> c) { if (N.isNullOrEmpty(c)) { return empty(); } return newStream(new ExceptionalIterator() { private final Iterator> iterators = c.iterator(); private ExceptionalStream cur; private ExceptionalIterator iter; @Override public boolean hasNext() throws E { while ((iter == null || iter.hasNext() == false) && iterators.hasNext()) { if (cur != null) { cur.close(); } cur = iterators.next(); iter = cur.elements; } return iter != null && iter.hasNext(); } @Override public T next() throws E { if ((iter == null || iter.hasNext() == false) && hasNext() == false) { throw new NoSuchElementException(); } return iter.next(); } }, mergeCloseHandlers(c)); } /** * Zip together the "a" and "b" arrays until one of them runs out of values. * Each pair of values is combined into a single value using the supplied zipFunction function. * * @param a * @param b * @return */ public static ExceptionalStream zip(final A[] a, final B[] b, final Throwables.BiFunction zipFunction) { return zip(ObjIterator.of(a), ObjIterator.of(b), zipFunction); } /** * Zip together the "a", "b" and "c" arrays until one of them runs out of values. * Each triple of values is combined into a single value using the supplied zipFunction function. * * @param a * @param b * @return */ public static ExceptionalStream zip(final A[] a, final B[] b, final C[] c, final Throwables.TriFunction zipFunction) { return zip(ObjIterator.of(a), ObjIterator.of(b), ObjIterator.of(c), zipFunction); } /** * Zip together the "a" and "b" arrays until one of them runs out of values. * Each pair of values is combined into a single value using the supplied zipFunction function. * * @param a * @param b * @return */ public static ExceptionalStream zip(final Collection a, final Collection b, final Throwables.BiFunction zipFunction) { return zip(N.iterate(a), N.iterate(b), zipFunction); } /** * Zip together the "a", "b" and "c" arrays until one of them runs out of values. * Each triple of values is combined into a single value using the supplied zipFunction function. * * @param a * @param b * @return */ public static ExceptionalStream zip(final Collection a, final Collection b, final Collection c, final Throwables.TriFunction zipFunction) { return zip(N.iterate(a), N.iterate(b), N.iterate(c), zipFunction); } /** * Zip together the "a" and "b" iterators until one of them runs out of values. * Each pair of values is combined into a single value using the supplied zipFunction function. * * @param a * @param b * @return */ public static ExceptionalStream zip(final Iterator a, final Iterator b, final Throwables.BiFunction zipFunction) { return newStream(new ExceptionalIterator() { @Override public boolean hasNext() throws E { return a.hasNext() && b.hasNext(); } @Override public T next() throws E { return zipFunction.apply(a.next(), b.next()); } }); } /** * Zip together the "a", "b" and "c" iterators until one of them runs out of values. * Each triple of values is combined into a single value using the supplied zipFunction function. * * @param a * @param b * @return */ public static ExceptionalStream zip(final Iterator a, final Iterator b, final Iterator c, final Throwables.TriFunction zipFunction) { return newStream(new ExceptionalIterator() { @Override public boolean hasNext() throws E { return a.hasNext() && b.hasNext() && c.hasNext(); } @Override public T next() throws E { return zipFunction.apply(a.next(), b.next(), c.next()); } }); } /** * Zip together the "a" and "b" streams until one of them runs out of values. * Each pair of values is combined into a single value using the supplied zipFunction function. * * @param a * @param b * @return */ public static ExceptionalStream zip(final ExceptionalStream a, final ExceptionalStream b, final Throwables.BiFunction zipFunction) { return newStream(new ExceptionalIterator() { private final ExceptionalIterator iterA = a.elements; private final ExceptionalIterator iterB = b.elements; @Override public boolean hasNext() throws E { return iterA.hasNext() && iterB.hasNext(); } @Override public T next() throws E { return zipFunction.apply(iterA.next(), iterB.next()); } }, mergeCloseHandlers(Array.asList(a, b))); } /** * Zip together the "a", "b" and "c" streams until one of them runs out of values. * Each triple of values is combined into a single value using the supplied zipFunction function. * * @param a * @param b * @param c * @return */ public static ExceptionalStream zip(final ExceptionalStream a, final ExceptionalStream b, final ExceptionalStream c, final Throwables.TriFunction zipFunction) { return newStream(new ExceptionalIterator() { private final ExceptionalIterator iterA = a.elements; private final ExceptionalIterator iterB = b.elements; private final ExceptionalIterator iterC = c.elements; @Override public boolean hasNext() throws E { return iterA.hasNext() && iterB.hasNext() && iterC.hasNext(); } @Override public T next() throws E { return zipFunction.apply(iterA.next(), iterB.next(), iterC.next()); } }, mergeCloseHandlers(Array.asList(a, b, c))); } /** * Zip together the "a" and "b" iterators until all of them runs out of values. * Each pair of values is combined into a single value using the supplied zipFunction function. * * @param a * @param b * @param valueForNoneA value to fill if "a" runs out of values first. * @param valueForNoneB value to fill if "b" runs out of values first. * @param zipFunction * @return */ public static ExceptionalStream zip(final A[] a, final B[] b, final A valueForNoneA, final B valueForNoneB, final Throwables.BiFunction zipFunction) { return zip(ObjIterator.of(a), ObjIterator.of(b), valueForNoneA, valueForNoneB, zipFunction); } /** * Zip together the "a", "b" and "c" iterators until all of them runs out of values. * Each triple of values is combined into a single value using the supplied zipFunction function. * * @param a * @param b * @param c * @param valueForNoneA value to fill if "a" runs out of values. * @param valueForNoneB value to fill if "b" runs out of values. * @param valueForNoneC value to fill if "c" runs out of values. * @param zipFunction * @return */ public static ExceptionalStream zip(final A[] a, final B[] b, final C[] c, final A valueForNoneA, final B valueForNoneB, final C valueForNoneC, final Throwables.TriFunction zipFunction) { return zip(ObjIterator.of(a), ObjIterator.of(b), ObjIterator.of(c), valueForNoneA, valueForNoneB, valueForNoneC, zipFunction); } /** * Zip together the "a" and "b" iterators until all of them runs out of values. * Each pair of values is combined into a single value using the supplied zipFunction function. * * @param a * @param b * @param valueForNoneA value to fill if "a" runs out of values first. * @param valueForNoneB value to fill if "b" runs out of values first. * @param zipFunction * @return */ public static ExceptionalStream zip(final Collection a, final Collection b, final A valueForNoneA, final B valueForNoneB, final Throwables.BiFunction zipFunction) { return zip(N.iterate(a), N.iterate(b), valueForNoneA, valueForNoneB, zipFunction); } /** * Zip together the "a", "b" and "c" iterators until all of them runs out of values. * Each triple of values is combined into a single value using the supplied zipFunction function. * * @param a * @param b * @param c * @param valueForNoneA value to fill if "a" runs out of values. * @param valueForNoneB value to fill if "b" runs out of values. * @param valueForNoneC value to fill if "c" runs out of values. * @param zipFunction * @return */ public static ExceptionalStream zip(final Collection a, final Collection b, final Collection c, final A valueForNoneA, final B valueForNoneB, final C valueForNoneC, final Throwables.TriFunction zipFunction) { return zip(N.iterate(a), N.iterate(b), N.iterate(c), valueForNoneA, valueForNoneB, valueForNoneC, zipFunction); } /** * Zip together the "a" and "b" iterators until all of them runs out of values. * Each pair of values is combined into a single value using the supplied zipFunction function. * * @param a * @param b * @param valueForNoneA value to fill if "a" runs out of values first. * @param valueForNoneB value to fill if "b" runs out of values first. * @param zipFunction * @return */ public static ExceptionalStream zip(final Iterator a, final Iterator b, final A valueForNoneA, final B valueForNoneB, final Throwables.BiFunction zipFunction) { return newStream(new ExceptionalIterator() { @Override public boolean hasNext() throws E { return a.hasNext() || b.hasNext(); } @Override public T next() throws E { if (hasNext() == false) { throw new NoSuchElementException(); } return zipFunction.apply(a.hasNext() ? a.next() : valueForNoneA, b.hasNext() ? b.next() : valueForNoneB); } }); } /** * Zip together the "a", "b" and "c" iterators until all of them runs out of values. * Each triple of values is combined into a single value using the supplied zipFunction function. * * @param a * @param b * @param c * @param valueForNoneA value to fill if "a" runs out of values. * @param valueForNoneB value to fill if "b" runs out of values. * @param valueForNoneC value to fill if "c" runs out of values. * @param zipFunction * @return */ public static ExceptionalStream zip(final Iterator a, final Iterator b, final Iterator c, final A valueForNoneA, final B valueForNoneB, final C valueForNoneC, final Throwables.TriFunction zipFunction) { return newStream(new ExceptionalIterator() { @Override public boolean hasNext() throws E { return a.hasNext() || b.hasNext() || c.hasNext(); } @Override public T next() throws E { if (hasNext() == false) { throw new NoSuchElementException(); } return zipFunction.apply(a.hasNext() ? a.next() : valueForNoneA, b.hasNext() ? b.next() : valueForNoneB, c.hasNext() ? c.next() : valueForNoneC); } }); } /** * Zip together the "a" and "b" streams until one of them runs out of values. * Each pair of values is combined into a single value using the supplied zipFunction function. * * @param a * @param b * @return */ public static ExceptionalStream zip(final ExceptionalStream a, final ExceptionalStream b, final A valueForNoneA, final B valueForNoneB, final Throwables.BiFunction zipFunction) { return newStream(new ExceptionalIterator() { private final ExceptionalIterator iterA = a.elements; private final ExceptionalIterator iterB = b.elements; @Override public boolean hasNext() throws E { return iterA.hasNext() || iterB.hasNext(); } @Override public T next() throws E { if (hasNext() == false) { throw new NoSuchElementException(); } return zipFunction.apply(iterA.hasNext() ? iterA.next() : valueForNoneA, iterB.hasNext() ? iterB.next() : valueForNoneB); } }, mergeCloseHandlers(Array.asList(a, b))); } /** * Zip together the "a", "b" and "c" streams until one of them runs out of values. * Each triple of values is combined into a single value using the supplied zipFunction function. * * @param a * @param b * @param c * @return */ public static ExceptionalStream zip(final ExceptionalStream a, final ExceptionalStream b, final ExceptionalStream c, final A valueForNoneA, final B valueForNoneB, final C valueForNoneC, final Throwables.TriFunction zipFunction) { return newStream(new ExceptionalIterator() { private final ExceptionalIterator iterA = a.elements; private final ExceptionalIterator iterB = b.elements; private final ExceptionalIterator iterC = c.elements; @Override public boolean hasNext() throws E { return iterA.hasNext() || iterB.hasNext() || iterC.hasNext(); } @Override public T next() throws E { if (hasNext() == false) { throw new NoSuchElementException(); } return zipFunction.apply(iterA.hasNext() ? iterA.next() : valueForNoneA, iterB.hasNext() ? iterB.next() : valueForNoneB, iterC.hasNext() ? iterC.next() : valueForNoneC); } }, mergeCloseHandlers(Array.asList(a, b, c))); } private static Deque> mergeCloseHandlers( Collection> closeHandlersList) { if (N.isNullOrEmpty(closeHandlersList)) { return null; } int count = 0; for (ExceptionalStream s : closeHandlersList) { count += N.size(s.closeHandlers); } if (count == 0) { return null; } final Deque> newCloseHandlers = new ArrayDeque<>(count); for (ExceptionalStream s : closeHandlersList) { if (N.notNullOrEmpty(s.closeHandlers)) { newCloseHandlers.addAll(s.closeHandlers); } } return newCloseHandlers; } /** * * @param predicate * @return */ @IntermediateOp public ExceptionalStream filter(final Throwables.Predicate predicate) { assertNotClosed(); return newStream(new ExceptionalIterator() { private boolean hasNext = false; private T next = null; @Override public boolean hasNext() throws E { if (hasNext == false) { while (elements.hasNext()) { next = elements.next(); if (predicate.test(next)) { hasNext = true; break; } } } return hasNext; } @Override public T next() throws E { if (hasNext == false && hasNext() == false) { throw new NoSuchElementException(); } hasNext = false; return next; } }, sorted, comparator, closeHandlers); } /** * * @param predicate * @param actionOnDroppedItem * @return */ @IntermediateOp public ExceptionalStream filter(final Throwables.Predicate predicate, final Throwables.Consumer actionOnDroppedItem) { assertNotClosed(); return filter(new Throwables.Predicate() { @Override public boolean test(T value) throws E { if (!predicate.test(value)) { actionOnDroppedItem.accept(value); return false; } return true; } }); } /** * * @param predicate * @return */ @IntermediateOp public ExceptionalStream takeWhile(final Throwables.Predicate predicate) { assertNotClosed(); return newStream(new ExceptionalIterator() { private boolean hasMore = true; private boolean hasNext = false; private T next = null; @Override public boolean hasNext() throws E { if (hasNext == false && hasMore && elements.hasNext()) { next = elements.next(); if (predicate.test(next)) { hasNext = true; } else { hasMore = false; } } return hasNext; } @Override public T next() throws E { if (hasNext == false && hasNext() == false) { throw new NoSuchElementException(); } hasNext = false; return next; } }, sorted, comparator, closeHandlers); } /** * * @param predicate * @return */ @IntermediateOp public ExceptionalStream dropWhile(final Throwables.Predicate predicate) { assertNotClosed(); return newStream(new ExceptionalIterator() { private boolean hasNext = false; private T next = null; private boolean dropped = false; @Override public boolean hasNext() throws E { if (hasNext == false) { if (dropped == false) { dropped = true; while (elements.hasNext()) { next = elements.next(); if (predicate.test(next) == false) { hasNext = true; break; } } } else if (elements.hasNext()) { next = elements.next(); hasNext = true; } } return hasNext; } @Override public T next() throws E { if (hasNext == false && hasNext() == false) { throw new NoSuchElementException(); } hasNext = false; return next; } }, sorted, comparator, closeHandlers); } /** * * @param predicate * @param actionOnDroppedItem * @return */ @IntermediateOp public ExceptionalStream dropWhile(final Throwables.Predicate predicate, final Throwables.Consumer actionOnDroppedItem) { assertNotClosed(); return filter(new Throwables.Predicate() { @Override public boolean test(T value) throws E { if (!predicate.test(value)) { actionOnDroppedItem.accept(value); return false; } return true; } }); } /** * * @param predicate * @return */ @IntermediateOp @Beta public ExceptionalStream skipUntil(final Throwables.Predicate predicate) { return dropWhile(Fnn.not(predicate)); } /** * Distinct and filter by occurrences. * * @return */ @IntermediateOp public ExceptionalStream distinct() { assertNotClosed(); final Set set = N.newHashSet(); return filter(new Throwables.Predicate() { @Override public boolean test(T value) { return set.add(hashKey(value)); } }); } /** * Distinct by the value mapped from keyMapper . * * @param keyMapper don't change value of the input parameter. * @return */ @IntermediateOp public ExceptionalStream distinctBy(final Throwables.Function keyMapper) { assertNotClosed(); final Set set = N.newHashSet(); return filter(new Throwables.Predicate() { @Override public boolean test(T value) throws E { return set.add(hashKey(keyMapper.apply(value))); } }); } /** * Distinct and filter by occurrences. * * @param keyMapper * @param occurrencesFilter * @return * @see #groupBy(Function, Collector) */ @IntermediateOp @TerminalOpTriggered @SuppressWarnings("rawtypes") public ExceptionalStream distinctBy(final Throwables.Function keyMapper, final Throwables.Predicate occurrencesFilter) { assertNotClosed(); final Supplier, Long>> supplier = Suppliers., Long> ofLinkedHashMap(); final Throwables.Function, E> keyedMapper = new Throwables.Function, E>() { @Override public Keyed apply(T t) throws E { return Keyed.of(keyMapper.apply(t), t); } }; final Throwables.Predicate, Long>, ? extends E> predicate = new Throwables.Predicate, Long>, E>() { @Override public boolean test(Map.Entry, Long> e) throws E { return occurrencesFilter.test(e.getValue()); } }; return groupBy(keyedMapper, Collectors.counting(), supplier).filter(predicate) .map((Throwables.Function, Long>, T, E>) (Throwables.Function) KK); } /** * Distinct and filter by occurrences. * * @param keyMapper * @param occurrencesFilter * @return * @see #groupBy(Function, Function, BinaryOperator) */ @IntermediateOp @TerminalOpTriggered public ExceptionalStream distinctBy(final Throwables.Function keyMapper, final Throwables.BinaryOperator mergeFunction) { assertNotClosed(); final Supplier> supplier = Suppliers. ofLinkedHashMap(); return groupBy(keyMapper, Fnn. identity(), mergeFunction, supplier).map(Fnn. value()); } /** * * @param * @param mapper * @return */ @IntermediateOp public ExceptionalStream map(final Throwables.Function mapper) { assertNotClosed(); return newStream(new ExceptionalIterator() { @Override public boolean hasNext() throws E { return elements.hasNext(); } @Override public U next() throws E { return mapper.apply(elements.next()); } }, closeHandlers); } /** * * @param * @param mapper * @return */ @IntermediateOp public ExceptionalStream flatMap( final Throwables.Function, ? extends E> mapper) { assertNotClosed(); final ExceptionalIterator iter = new ExceptionalIterator() { private ExceptionalIterator cur = null; private ExceptionalStream s = null; private Deque> closeHandle = null; @Override public boolean hasNext() throws E { while (cur == null || cur.hasNext() == false) { if (elements.hasNext()) { if (closeHandle != null) { final Deque> tmp = closeHandle; closeHandle = null; ExceptionalStream.close(tmp); } s = mapper.apply(elements.next()); if (N.notNullOrEmpty(s.closeHandlers)) { closeHandle = s.closeHandlers; } cur = s.elements; } else { cur = null; break; } } return cur != null && cur.hasNext(); } @Override public R next() throws E { if ((cur == null || cur.hasNext() == false) && hasNext() == false) { throw new NoSuchElementException(); } return cur.next(); } @Override public void close() throws E { if (closeHandle != null) { ExceptionalStream.close(closeHandle); } } }; final Deque> newCloseHandlers = new ArrayDeque<>(N.size(closeHandlers) + 1); newCloseHandlers.add(new Throwables.Runnable() { @Override public void run() throws E { iter.close(); } }); if (N.notNullOrEmpty(closeHandlers)) { newCloseHandlers.addAll(closeHandlers); } return newStream(iter, newCloseHandlers); } /** * * @param * @param mapper * @return */ @IntermediateOp public ExceptionalStream flattMap(final Throwables.Function, ? extends E> mapper) { assertNotClosed(); return newStream(new ExceptionalIterator() { private Iterator cur = null; private Collection c = null; @Override public boolean hasNext() throws E { while ((cur == null || cur.hasNext() == false) && elements.hasNext()) { c = mapper.apply(elements.next()); cur = N.isNullOrEmpty(c) ? null : c.iterator(); } return cur != null && cur.hasNext(); } @Override public R next() throws E { if ((cur == null || cur.hasNext() == false) && hasNext() == false) { throw new NoSuchElementException(); } return cur.next(); } }, closeHandlers); } // /** // * // * @param mapper // * @return // */ // @IntermediateOp // public ExceptionalStream flattMapToInt(final Throwables.Function mapper) { // final Throwables.Function, E> mapper2 = new Throwables.Function, E>() { // @Override // public ExceptionalStream apply(T t) throws E { // return ExceptionalStream.of(mapper.apply(t)); // } // }; // // return flatMap(mapper2); // } // // /** // * // * @param mapper // * @return // */ // @IntermediateOp // public ExceptionalStream flattMapToLong(final Throwables.Function mapper) { // final Throwables.Function, E> mapper2 = new Throwables.Function, E>() { // @Override // public ExceptionalStream apply(T t) throws E { // return ExceptionalStream.of(mapper.apply(t)); // } // }; // // return flatMap(mapper2); // } // // /** // * // * @param mapper // * @return // */ // @IntermediateOp // public ExceptionalStream flattMapToDouble(final Throwables.Function mapper) { // final Throwables.Function, E> mapper2 = new Throwables.Function, E>() { // @Override // public ExceptionalStream apply(T t) throws E { // return ExceptionalStream.of(mapper.apply(t)); // } // }; // // return flatMap(mapper2); // } /** * * @param * @param mapper * @return */ @IntermediateOp public ExceptionalStream slidingMap(Throwables.BiFunction mapper) { return slidingMap(mapper, 1); } /** * * @param * @param mapper * @param increment * @return */ @IntermediateOp public ExceptionalStream slidingMap(Throwables.BiFunction mapper, int increment) { return slidingMap(mapper, increment, false); } /** * * @param * @param mapper * @param increment * @param ignoreNotPaired * @return */ @IntermediateOp public ExceptionalStream slidingMap(final Throwables.BiFunction mapper, final int increment, final boolean ignoreNotPaired) { assertNotClosed(); checkArgPositive(increment, "increment"); final int windowSize = 2; return newStream(new ExceptionalIterator() { @SuppressWarnings("unchecked") private final T NONE = (T) N.NULL_MASK; private T prev = NONE; private T _1 = NONE; @Override public boolean hasNext() throws E { if (increment > windowSize && prev != NONE) { int skipNum = increment - windowSize; while (skipNum-- > 0 && elements.hasNext()) { elements.next(); } prev = NONE; } if (ignoreNotPaired && _1 == NONE && elements.hasNext()) { _1 = elements.next(); } return elements.hasNext(); } @Override public R next() throws E { if (hasNext() == false) { throw new NoSuchElementException(); } if (ignoreNotPaired) { final R res = mapper.apply(_1, (prev = elements.next())); _1 = increment == 1 ? prev : NONE; return res; } else { if (increment == 1) { return mapper.apply(prev == NONE ? elements.next() : prev, (prev = (elements.hasNext() ? elements.next() : null))); } else { return mapper.apply(elements.next(), (prev = (elements.hasNext() ? elements.next() : null))); } } } }, closeHandlers); } /** * * @param * @param mapper * @return */ @IntermediateOp public ExceptionalStream slidingMap(Throwables.TriFunction mapper) { return slidingMap(mapper, 1); } /** * * @param * @param mapper * @param increment * @return */ @IntermediateOp public ExceptionalStream slidingMap(Throwables.TriFunction mapper, int increment) { return slidingMap(mapper, increment, false); } /** * * @param * @param mapper * @param increment * @param ignoreNotPaired * @return */ @IntermediateOp public ExceptionalStream slidingMap(final Throwables.TriFunction mapper, final int increment, final boolean ignoreNotPaired) { assertNotClosed(); checkArgPositive(increment, "increment"); final int windowSize = 3; return newStream(new ExceptionalIterator() { @SuppressWarnings("unchecked") private final T NONE = (T) N.NULL_MASK; private T prev = NONE; private T prev2 = NONE; private T _1 = NONE; private T _2 = NONE; @Override public boolean hasNext() throws E { if (increment > windowSize && prev != NONE) { int skipNum = increment - windowSize; while (skipNum-- > 0 && elements.hasNext()) { elements.next(); } prev = NONE; } if (ignoreNotPaired) { if (_1 == NONE && elements.hasNext()) { _1 = elements.next(); } if (_2 == NONE && elements.hasNext()) { _2 = elements.next(); } } return elements.hasNext(); } @Override public R next() throws E { if (hasNext() == false) { throw new NoSuchElementException(); } if (ignoreNotPaired) { final R res = mapper.apply(_1, _2, (prev = elements.next())); _1 = increment == 1 ? _2 : (increment == 2 ? prev : NONE); _2 = increment == 1 ? prev : NONE; return res; } else { if (increment == 1) { return mapper.apply(prev2 == NONE ? elements.next() : prev2, (prev2 = (prev == NONE ? (elements.hasNext() ? elements.next() : null) : prev)), (prev = (elements.hasNext() ? elements.next() : null))); } else if (increment == 2) { return mapper.apply(prev == NONE ? elements.next() : prev, elements.hasNext() ? elements.next() : null, (prev = (elements.hasNext() ? elements.next() : null))); } else { return mapper.apply(elements.next(), elements.hasNext() ? elements.next() : null, (prev = (elements.hasNext() ? elements.next() : null))); } } } }, closeHandlers); } /** * * @param the key type * @param keyMapper * @return */ @IntermediateOp @TerminalOpTriggered public ExceptionalStream>, E> groupBy(final Throwables.Function keyMapper) { return groupBy(keyMapper, Suppliers.> ofMap()); } /** * * @param the key type * @param keyMapper * @param mapFactory * @return */ @IntermediateOp @TerminalOpTriggered public ExceptionalStream>, E> groupBy(final Throwables.Function keyMapper, final Supplier>> mapFactory) { return groupBy(keyMapper, Fnn. identity(), mapFactory); } /** * * @param the key type * @param the value type * @param keyMapper * @param valueMapper * @return * @see Collectors#toMultimap(Function, Function) */ @IntermediateOp @TerminalOpTriggered public ExceptionalStream>, E> groupBy(Throwables.Function keyMapper, Throwables.Function valueMapper) { return groupBy(keyMapper, valueMapper, Suppliers.> ofMap()); } /** * * @param the key type * @param the value type * @param keyMapper * @param valueMapper * @param mapFactory * @return * @see Collectors#toMultimap(Function, Function, Supplier) */ @IntermediateOp @TerminalOpTriggered public ExceptionalStream>, E> groupBy(final Throwables.Function keyMapper, final Throwables.Function valueMapper, final Supplier>> mapFactory) { assertNotClosed(); return newStream(new ExceptionalIterator>, E>() { private Iterator>> iter = null; @Override public boolean hasNext() throws E { init(); return iter.hasNext(); } @Override public Map.Entry> next() throws E { init(); return iter.next(); } private void init() throws E { if (iter == null) { iter = ExceptionalStream.this.groupTo(keyMapper, valueMapper, mapFactory).entrySet().iterator(); } } }, closeHandlers); } /** * * @param the key type * @param the value type * @param keyMapper * @param valueMapper * @param mergeFunction * @return */ @IntermediateOp @TerminalOpTriggered public ExceptionalStream, E> groupBy(final Throwables.Function keyMapper, final Throwables.Function valueMapper, Throwables.BinaryOperator mergeFunction) { return groupBy(keyMapper, valueMapper, mergeFunction, Suppliers. ofMap()); } /** * * @param the key type * @param the value type * @param keyMapper * @param valueMapper * @param mergeFunction * @param mapFactory * @return * @see {@link Fn.Fnn#throwingMerger()} * @see {@link Fn.Fnn#replacingMerger()} * @see {@link Fn.Fnn#ignoringMerger()} */ @IntermediateOp @TerminalOpTriggered public ExceptionalStream, E> groupBy(final Throwables.Function keyMapper, final Throwables.Function valueMapper, final Throwables.BinaryOperator mergeFunction, final Supplier> mapFactory) { assertNotClosed(); return newStream(new ExceptionalIterator, E>() { private Iterator> iter = null; @Override public boolean hasNext() throws E { init(); return iter.hasNext(); } @Override public Map.Entry next() throws E { init(); return iter.next(); } private void init() throws E { if (iter == null) { iter = ExceptionalStream.this.toMap(keyMapper, valueMapper, mergeFunction, mapFactory).entrySet().iterator(); } } }, closeHandlers); } /** * * @param the key type * @param * @param * @param keyMapper * @param downstream * @return * @throws E the e */ @IntermediateOp @TerminalOpTriggered public ExceptionalStream, E> groupBy(final Throwables.Function keyMapper, final Collector downstream) { return groupBy(keyMapper, downstream, Suppliers. ofMap()); } /** * * @param the key type * @param * @param * @param keyMapper * @param downstream * @param mapFactory * @return * @throws E the e */ @IntermediateOp @TerminalOpTriggered public ExceptionalStream, E> groupBy(final Throwables.Function keyMapper, final Collector downstream, final Supplier> mapFactory) { return groupBy(keyMapper, Fnn. identity(), downstream, mapFactory); } /** * * @param the key type * @param the value type * @param * @param * @param keyMapper * @param valueMapper * @param downstream * @return * @throws E the e */ @IntermediateOp @TerminalOpTriggered public ExceptionalStream, E> groupBy(final Throwables.Function keyMapper, final Throwables.Function valueMapper, final Collector downstream) { return groupBy(keyMapper, valueMapper, downstream, Suppliers. ofMap()); } /** * * @param the key type * @param the value type * @param * @param * @param keyMapper * @param valueMapper * @param downstream * @param mapFactory * @return * @throws E the e */ @IntermediateOp @TerminalOpTriggered public ExceptionalStream, E> groupBy(final Throwables.Function keyMapper, final Throwables.Function valueMapper, final Collector downstream, final Supplier> mapFactory) { assertNotClosed(); return newStream(new ExceptionalIterator, E>() { private Iterator> iter = null; @Override public boolean hasNext() throws E { init(); return iter.hasNext(); } @Override public Map.Entry next() throws E { init(); return iter.next(); } private void init() throws E { if (iter == null) { iter = ExceptionalStream.this.toMap(keyMapper, valueMapper, downstream, mapFactory).entrySet().iterator(); } } }, closeHandlers); } /** * * @param * @param keyMapper * @return */ @IntermediateOp @TerminalOpTriggered public ExceptionalStream, E> countBy(final Throwables.Function keyMapper) { return groupBy(keyMapper, Collectors.countingInt()); } /** * * @param * @param collapsible * @param supplier * @return */ @IntermediateOp public > ExceptionalStream collapse(final Throwables.BiPredicate collapsible, final Supplier supplier) { assertNotClosed(); final ExceptionalIterator iter = elements; return newStream(new ExceptionalIterator() { private boolean hasNext = false; private T next = null; @Override public boolean hasNext() throws E { return hasNext || iter.hasNext(); } @Override public C next() throws E { if (hasNext == false) { next = iter.next(); } final C c = supplier.get(); c.add(next); while ((hasNext = iter.hasNext())) { if (collapsible.test(next, (next = iter.next()))) { c.add(next); } else { break; } } return c; } }, closeHandlers); } /** * Merge series of adjacent elements which satisfy the given predicate using * the merger function and return a new stream. * *

Example: *

     * 
     * Stream.of(new Integer[0]).collapse((a, b) -> a < b, (a, b) -> a + b) => []
     * Stream.of(1).collapse((a, b) -> a < b, (a, b) -> a + b) => [1]
     * Stream.of(1, 2).collapse((a, b) -> a < b, (a, b) -> a + b) => [3]
     * Stream.of(1, 2, 3).collapse((a, b) -> a < b, (a, b) -> a + b) => [6]
     * Stream.of(1, 2, 3, 3, 2, 1).collapse((a, b) -> a < b, (a, b) -> a + b) => [6, 3, 2, 1]
     * 
     * 
* *
* This method only run sequentially, even in parallel stream. * * @param collapsible * @param mergeFunction * @return */ @IntermediateOp public ExceptionalStream collapse(final Throwables.BiPredicate collapsible, final Throwables.BiFunction mergeFunction) { assertNotClosed(); final ExceptionalIterator iter = elements; return newStream(new ExceptionalIterator() { private boolean hasNext = false; private T next = null; @Override public boolean hasNext() throws E { return hasNext || iter.hasNext(); } @Override public T next() throws E { T res = hasNext ? next : (next = iter.next()); while ((hasNext = iter.hasNext())) { if (collapsible.test(next, (next = iter.next()))) { res = mergeFunction.apply(res, next); } else { break; } } return res; } }, closeHandlers); } /** * * @param * @param collapsible * @param init * @param op * @return */ @IntermediateOp public ExceptionalStream collapse(final Throwables.BiPredicate collapsible, final U init, final Throwables.BiFunction op) { assertNotClosed(); final ExceptionalIterator iter = elements; return newStream(new ExceptionalIterator() { private boolean hasNext = false; private T next = null; @Override public boolean hasNext() throws E { return hasNext || iter.hasNext(); } @Override public U next() throws E { U res = op.apply(init, hasNext ? next : (next = iter.next())); while ((hasNext = iter.hasNext())) { if (collapsible.test(next, (next = iter.next()))) { res = op.apply(res, next); } else { break; } } return res; } }, closeHandlers); } /** * * @param * @param collapsible * @param supplier * @param accumulator * @return */ @IntermediateOp public ExceptionalStream collapse(final Throwables.BiPredicate collapsible, final Throwables.Supplier supplier, final Throwables.BiConsumer accumulator) { assertNotClosed(); final ExceptionalIterator iter = elements; return newStream(new ExceptionalIterator() { private boolean hasNext = false; private T next = null; @Override public boolean hasNext() throws E { return hasNext || iter.hasNext(); } @Override public R next() throws E { final R container = supplier.get(); accumulator.accept(container, hasNext ? next : (next = iter.next())); while ((hasNext = iter.hasNext())) { if (collapsible.test(next, (next = iter.next()))) { accumulator.accept(container, next); } else { break; } } return container; } }, closeHandlers); } /** * * @param * @param
* @param collapsible * @param collector * @return */ @IntermediateOp public ExceptionalStream collapse(final Throwables.BiPredicate collapsible, final Collector collector) { assertNotClosed(); final Supplier supplier = collector.supplier(); final BiConsumer accumulator = collector.accumulator(); final Function finisher = collector.finisher(); final ExceptionalIterator iter = elements; return newStream(new ExceptionalIterator() { private boolean hasNext = false; private T next = null; @Override public boolean hasNext() throws E { return hasNext || iter.hasNext(); } @Override public R next() throws E { final A container = supplier.get(); accumulator.accept(container, hasNext ? next : (next = iter.next())); while ((hasNext = iter.hasNext())) { if (collapsible.test(next, (next = iter.next()))) { accumulator.accept(container, next); } else { break; } } return finisher.apply(container); } }, closeHandlers); } /** * * @param accumulator * @return */ @IntermediateOp public ExceptionalStream scan(final Throwables.BiFunction accumulator) { assertNotClosed(); final ExceptionalIterator iter = elements; return newStream(new ExceptionalIterator() { private T res = null; private boolean isFirst = true; @Override public boolean hasNext() throws E { return iter.hasNext(); } @Override public T next() throws E { if (isFirst) { isFirst = false; return (res = iter.next()); } else { return (res = accumulator.apply(res, iter.next())); } } }, closeHandlers); } /** * * @param * @param init * @param accumulator * @return */ @IntermediateOp public ExceptionalStream scan(final U init, final Throwables.BiFunction accumulator) { assertNotClosed(); final ExceptionalIterator iter = elements; return newStream(new ExceptionalIterator() { private U res = init; @Override public boolean hasNext() throws E { return iter.hasNext(); } @Override public U next() throws E { return (res = accumulator.apply(res, iter.next())); } }, closeHandlers); } /** * * @param * @param init * @param accumulator * @param initIncluded * @return */ @IntermediateOp public ExceptionalStream scan(final U init, final Throwables.BiFunction accumulator, final boolean initIncluded) { assertNotClosed(); if (initIncluded == false) { return scan(init, accumulator); } final ExceptionalIterator iter = elements; return newStream(new ExceptionalIterator() { private boolean isFirst = true; private U res = init; @Override public boolean hasNext() throws E { return isFirst || iter.hasNext(); } @Override public U next() throws E { if (isFirst) { isFirst = false; return init; } return (res = accumulator.apply(res, iter.next())); } }, closeHandlers); } /** * * @param defaultValue * @return * @see #appendIfEmpty(Object...) */ @IntermediateOp public final ExceptionalStream defaultIfEmpty(final T defaultValue) { return appendIfEmpty(defaultValue); } /** * * @param supplier * @return * @see #appendIfEmpty(Supplier) */ @IntermediateOp public final ExceptionalStream defaultIfEmpty(final Supplier> supplier) { return appendIfEmpty(supplier); } @IntermediateOp @SafeVarargs public final ExceptionalStream prepend(final T... a) { return prepend(ExceptionalStream. of(a)); } @IntermediateOp public ExceptionalStream prepend(final Collection c) { return prepend(ExceptionalStream. of(c)); } /** * * @param s * @return */ @IntermediateOp public ExceptionalStream prepend(final ExceptionalStream s) { assertNotClosed(); return concat(s, this); } @IntermediateOp @SafeVarargs public final ExceptionalStream append(final T... a) { return append(ExceptionalStream. of(a)); } @IntermediateOp public ExceptionalStream append(final Collection c) { return append(ExceptionalStream. of(c)); } /** * * @param s * @return */ @IntermediateOp public ExceptionalStream append(final ExceptionalStream s) { assertNotClosed(); return concat(this, s); } @IntermediateOp @SafeVarargs public final ExceptionalStream appendIfEmpty(final T... a) { return appendIfEmpty(Arrays.asList(a)); } @IntermediateOp public ExceptionalStream appendIfEmpty(final Collection c) { assertNotClosed(); if (N.isNullOrEmpty(c)) { return newStream(elements, closeHandlers); } return newStream(new ExceptionalIterator() { private ExceptionalIterator iter; @Override public boolean hasNext() throws E { if (iter == null) { init(); } return iter.hasNext(); } @Override public T next() throws E { if (iter == null) { init(); } return iter.next(); } @Override public void skip(long n) throws E { if (iter == null) { init(); } iter.skip(n); } @Override public long count() throws E { if (iter == null) { init(); } return iter.count(); } private void init() throws E { if (iter == null) { if (elements.hasNext()) { iter = elements; } else { iter = ExceptionalIterator.wrap(c.iterator()); } } } }, closeHandlers); } /** * Append if empty. * * @param supplier * @return * @throws E the e */ @IntermediateOp public ExceptionalStream appendIfEmpty(final Supplier> supplier) { assertNotClosed(); final Holder> holder = new Holder<>(); return newStream(new ExceptionalIterator() { private ExceptionalIterator iter; @Override public boolean hasNext() throws E { if (iter == null) { init(); } return iter.hasNext(); } @Override public T next() throws E { if (iter == null) { init(); } return iter.next(); } @Override public void skip(long n) throws E { if (iter == null) { init(); } iter.skip(n); } @Override public long count() throws E { if (iter == null) { init(); } return iter.count(); } private void init() throws E { if (iter == null) { if (elements.hasNext()) { iter = elements; } else { final ExceptionalStream s = supplier.get(); holder.setValue(s); iter = s.iterator(); } } } }, closeHandlers).onClose(new Throwables.Runnable() { @Override public void run() throws E { close(holder); } }); } void close(Holder> holder) throws E { if (holder.value() != null) { holder.value().close(); } } @TerminalOp public Optional applyIfNotEmpty(final Throwables.Function, R, ? extends E> func) throws E { assertNotClosed(); try { if (elements.hasNext()) { return Optional.of(func.apply(this)); } else { return Optional.empty(); } } finally { close(); } } @TerminalOp public OrElse acceptIfNotEmpty(Throwables.Consumer, ? extends E> action) throws E { assertNotClosed(); try { if (elements.hasNext()) { action.accept(this); return OrElse.TRUE; } } finally { close(); } return OrElse.FALSE; } /** * * @param action * @return */ @IntermediateOp public ExceptionalStream onEach(final Throwables.Consumer action) { return peek(action); } /** * * @param action * @return */ @IntermediateOp public ExceptionalStream peek(final Throwables.Consumer action) { assertNotClosed(); return newStream(new ExceptionalIterator() { @Override public boolean hasNext() throws E { return elements.hasNext(); } @Override public T next() throws E { final T next = elements.next(); action.accept(next); return next; } }, sorted, comparator, closeHandlers); } /** * Returns ExceptionalStream of {@code List} with consecutive sub sequences of the elements, each of the same size (the final sequence may be smaller). * * * @param chunkSize the desired size of each sub sequence (the last may be smaller). * @return */ @IntermediateOp public ExceptionalStream, E> splitToList(final int chunkSize) { return split(chunkSize, Factory. ofList()); } /** * Returns ExceptionalStream of {@code Set} with consecutive sub sequences of the elements, each of the same size (the final sequence may be smaller). * * * @param chunkSize the desired size of each sub sequence (the last may be smaller). * @return */ @IntermediateOp public ExceptionalStream, E> splitToSet(final int chunkSize) { return split(chunkSize, Factory. ofSet()); } /** * Returns ExceptionalStream of {@code C} with consecutive sub sequences of the elements, each of the same size (the final sequence may be smaller). * * * @param * @param chunkSize the desired size of each sub sequence (the last may be smaller). * @param collectionSupplier * @return */ @IntermediateOp public > ExceptionalStream split(final int chunkSize, final IntFunction collectionSupplier) { assertNotClosed(); checkArgPositive(chunkSize, "chunkSize"); return newStream(new ExceptionalIterator() { @Override public boolean hasNext() throws E { return elements.hasNext(); } @Override public C next() throws E { if (hasNext() == false) { throw new NoSuchElementException(); } final C result = collectionSupplier.apply(chunkSize); int cnt = 0; while (cnt++ < chunkSize && elements.hasNext()) { result.add(elements.next()); } return result; } @Override public long count() throws E { final long len = elements.count(); return len % chunkSize == 0 ? len / chunkSize : len / chunkSize + 1; } @Override public void skip(long n) throws E { checkArgNotNegative(n, "n"); elements.skip(n > Long.MAX_VALUE / chunkSize ? Long.MAX_VALUE : n * chunkSize); } }, closeHandlers); } /** * * @param * @param * @param chunkSize the desired size of each sub sequence (the last may be smaller). * @param collector * @return */ @IntermediateOp public ExceptionalStream split(final int chunkSize, final Collector collector) { assertNotClosed(); checkArgPositive(chunkSize, "chunkSize"); final Supplier supplier = collector.supplier(); final BiConsumer accumulator = collector.accumulator(); final Function finisher = collector.finisher(); return newStream(new ExceptionalIterator() { @Override public boolean hasNext() throws E { return elements.hasNext(); } @Override public R next() throws E { if (hasNext() == false) { throw new NoSuchElementException(); } final A container = supplier.get(); int cnt = 0; while (cnt++ < chunkSize && elements.hasNext()) { accumulator.accept(container, elements.next()); } return finisher.apply(container); } @Override public long count() throws E { final long len = elements.count(); return len % chunkSize == 0 ? len / chunkSize : len / chunkSize + 1; } @Override public void skip(long n) throws E { checkArgNotNegative(n, "n"); elements.skip(n > Long.MAX_VALUE / chunkSize ? Long.MAX_VALUE : n * chunkSize); } }, closeHandlers); } /** * Sliding to list. * * @param windowSize * @param increment * @return */ @IntermediateOp public ExceptionalStream, E> slidingToList(final int windowSize, final int increment) { return sliding(windowSize, increment, Factory. ofList()); } /** * Sliding to set. * * @param windowSize * @param increment * @return */ @IntermediateOp public ExceptionalStream, E> slidingToSet(final int windowSize, final int increment) { return sliding(windowSize, increment, Factory. ofSet()); } /** * * @param * @param windowSize * @param increment * @param collectionSupplier * @return */ @IntermediateOp public > ExceptionalStream sliding(final int windowSize, final int increment, final IntFunction collectionSupplier) { assertNotClosed(); checkArgument(windowSize > 0 && increment > 0, "windowSize=%s and increment=%s must be bigger than 0", windowSize, increment); return newStream(new ExceptionalIterator() { private Deque queue = null; private boolean toSkip = false; @Override public boolean hasNext() throws E { if (toSkip) { int skipNum = increment - windowSize; while (skipNum-- > 0 && elements.hasNext()) { elements.next(); } toSkip = false; } return elements.hasNext(); } @Override public C next() throws E { if (hasNext() == false) { throw new NoSuchElementException(); } if (queue == null) { queue = new ArrayDeque<>(N.max(0, windowSize - increment)); } final C result = collectionSupplier.apply(windowSize); int cnt = 0; if (queue.size() > 0 && increment < windowSize) { cnt = queue.size(); for (T e : queue) { result.add(e); } if (queue.size() <= increment) { queue.clear(); } else { for (int i = 0; i < increment; i++) { queue.removeFirst(); } } } T next = null; while (cnt++ < windowSize && elements.hasNext()) { next = elements.next(); result.add(next); if (cnt > increment) { queue.add(next); } } toSkip = increment > windowSize; return result; } @Override public long count() throws E { final int prevSize = increment >= windowSize ? 0 : (queue == null ? 0 : queue.size()); final long len = prevSize + elements.count(); if (len == prevSize) { return 0; } else if (len <= windowSize) { return 1; } else { final long rlen = len - windowSize; return 1 + (rlen % increment == 0 ? rlen / increment : rlen / increment + 1); } } @Override public void skip(long n) throws E { checkArgNotNegative(n, "n"); if (n == 0) { return; } if (increment >= windowSize) { elements.skip(n > Long.MAX_VALUE / increment ? Long.MAX_VALUE : n * increment); } else { if (N.isNullOrEmpty(queue)) { final long m = ((n - 1) > Long.MAX_VALUE / increment ? Long.MAX_VALUE : (n - 1) * increment); elements.skip(m); } else { final long m = (n > Long.MAX_VALUE / increment ? Long.MAX_VALUE : n * increment); final int prevSize = increment >= windowSize ? 0 : (queue == null ? 0 : queue.size()); if (m < prevSize) { for (int i = 0; i < m; i++) { queue.removeFirst(); } } else { if (queue != null) { queue.clear(); } elements.skip(m - prevSize); } } if (queue == null) { queue = new ArrayDeque<>(windowSize); } int cnt = queue.size(); while (cnt++ < windowSize && elements.hasNext()) { queue.add(elements.next()); } } } }, closeHandlers); } /** * * @param * @param * @param windowSize * @param increment * @param collector * @return */ @IntermediateOp public ExceptionalStream sliding(final int windowSize, final int increment, final Collector collector) { assertNotClosed(); checkArgument(windowSize > 0 && increment > 0, "windowSize=%s and increment=%s must be bigger than 0", windowSize, increment); final Supplier supplier = collector.supplier(); final BiConsumer accumulator = collector.accumulator(); final Function finisher = collector.finisher(); return newStream(new ExceptionalIterator() { private Deque queue = null; private boolean toSkip = false; @Override public boolean hasNext() throws E { if (toSkip) { int skipNum = increment - windowSize; while (skipNum-- > 0 && elements.hasNext()) { elements.next(); } toSkip = false; } return elements.hasNext(); } @Override public R next() throws E { if (hasNext() == false) { throw new NoSuchElementException(); } if (increment < windowSize && queue == null) { queue = new ArrayDeque<>(windowSize - increment); } final A container = supplier.get(); int cnt = 0; if (increment < windowSize && queue.size() > 0) { cnt = queue.size(); for (T e : queue) { accumulator.accept(container, e); } if (queue.size() <= increment) { queue.clear(); } else { for (int i = 0; i < increment; i++) { queue.removeFirst(); } } } T next = null; while (cnt++ < windowSize && elements.hasNext()) { next = elements.next(); accumulator.accept(container, next); if (cnt > increment) { queue.add(next); } } toSkip = increment > windowSize; return finisher.apply(container); } @Override public long count() throws E { final int prevSize = increment >= windowSize ? 0 : (queue == null ? 0 : queue.size()); final long len = prevSize + elements.count(); if (len == prevSize) { return 0; } else if (len <= windowSize) { return 1; } else { final long rlen = len - windowSize; return 1 + (rlen % increment == 0 ? rlen / increment : rlen / increment + 1); } } @Override public void skip(long n) throws E { checkArgNotNegative(n, "n"); if (n == 0) { return; } if (increment >= windowSize) { elements.skip(n > Long.MAX_VALUE / increment ? Long.MAX_VALUE : n * increment); } else { if (N.isNullOrEmpty(queue)) { final long m = ((n - 1) > Long.MAX_VALUE / increment ? Long.MAX_VALUE : (n - 1) * increment); elements.skip(m); } else { final long m = (n > Long.MAX_VALUE / increment ? Long.MAX_VALUE : n * increment); final int prevSize = increment >= windowSize ? 0 : (queue == null ? 0 : queue.size()); if (m < prevSize) { for (int i = 0; i < m; i++) { queue.removeFirst(); } } else { if (queue != null) { queue.clear(); } elements.skip(m - prevSize); } } if (queue == null) { queue = new ArrayDeque<>(windowSize); } int cnt = queue.size(); while (cnt++ < windowSize && elements.hasNext()) { queue.add(elements.next()); } } } }, closeHandlers); } /** * * @param n * @return */ @IntermediateOp public ExceptionalStream skip(final long n) { assertNotClosed(); checkArgNotNegative(n, "n"); return newStream(new ExceptionalIterator() { private boolean skipped = false; @Override public boolean hasNext() throws E { if (skipped == false) { skipped = true; skip(n); } return elements.hasNext(); } @Override public T next() throws E { if (skipped == false) { skipped = true; skip(n); } return elements.next(); } }, sorted, comparator, closeHandlers); } @IntermediateOp public ExceptionalStream skipNull() { return filter(Fnn. notNull()); } /** * * @param maxSize * @return */ @IntermediateOp public ExceptionalStream limit(final long maxSize) { assertNotClosed(); checkArgNotNegative(maxSize, "maxSize"); return newStream(new ExceptionalIterator() { private long cnt = 0; @Override public boolean hasNext() throws E { return cnt < maxSize && elements.hasNext(); } @Override public T next() throws E { if (cnt >= maxSize) { throw new NoSuchElementException(); } cnt++; return elements.next(); } }, sorted, comparator, closeHandlers); } // /** // * // * @param from // * @param to // * @return // * @deprecated // */ // @Deprecated // public ExceptionalStream slice(final long from, final long to) { // checkArgNotNegative(from, "from"); // checkArgNotNegative(to, "to"); // checkArgument(to >= from, "'to' can't be less than `from`"); // // return from == 0 ? limit(to) : skip(from).limit(to - from); // } @IntermediateOp @TerminalOpTriggered public ExceptionalStream reversed() { assertNotClosed(); return newStream(new ExceptionalIterator() { private boolean initialized = false; private T[] aar; private int cursor; @Override public boolean hasNext() throws E { if (initialized == false) { init(); } return cursor > 0; } @Override public T next() throws E { if (initialized == false) { init(); } if (cursor <= 0) { throw new NoSuchElementException(); } return aar[--cursor]; } @Override public long count() throws E { if (initialized == false) { init(); } return cursor; } @Override public void skip(long n) throws E { if (initialized == false) { init(); } cursor = n < cursor ? cursor - (int) n : 0; } private void init() throws E { if (initialized == false) { initialized = true; aar = (T[]) ExceptionalStream.this.toArray(false); cursor = aar.length; } } }, false, null, closeHandlers); } @IntermediateOp @TerminalOpTriggered public ExceptionalStream rotated(final int distance) { assertNotClosed(); if (distance == 0) { return newStream(elements, closeHandlers); } return newStream(new ExceptionalIterator() { private boolean initialized = false; private T[] aar; private int len; private int start; private int cnt = 0; @Override public boolean hasNext() throws E { if (initialized == false) { init(); } return cnt < len; } @Override public T next() throws E { if (hasNext() == false) { throw new NoSuchElementException(); } return aar[(start + cnt++) % len]; } @Override public long count() throws E { if (initialized == false) { init(); } return len - cnt; } @Override public void skip(long n) throws E { if (initialized == false) { init(); } cnt = n < len - cnt ? cnt + (int) n : len; } private void init() throws E { if (initialized == false) { initialized = true; aar = (T[]) ExceptionalStream.this.toArray(false); len = aar.length; if (len > 0) { start = distance % len; if (start < 0) { start += len; } start = len - start; } } } }, false, null, closeHandlers); } @IntermediateOp @TerminalOpTriggered public ExceptionalStream shuffled() { return shuffled(RAND); } @IntermediateOp @TerminalOpTriggered public ExceptionalStream shuffled(final Random rnd) { assertNotClosed(); return lazyLoad(new Function() { @Override public Object[] apply(final Object[] a) { N.shuffle(a, rnd); return a; } }, false, null); } @IntermediateOp @TerminalOpTriggered public ExceptionalStream sorted() { return sorted(Comparators.NATURAL_ORDER); } @IntermediateOp @TerminalOpTriggered public ExceptionalStream reverseSorted() { return sorted(Comparators.REVERSED_ORDER); } /** * * @param comparator * @return */ @IntermediateOp @TerminalOpTriggered public ExceptionalStream sorted(final Comparator comparator) { assertNotClosed(); final Comparator cmp = comparator == null ? Comparators.NATURAL_ORDER : comparator; if (sorted && cmp == this.comparator) { return newStream(elements, sorted, comparator, closeHandlers); } return lazyLoad(new Function() { @Override public Object[] apply(final Object[] a) { N.sort((T[]) a, cmp); return a; } }, true, cmp); } /** * * @param keyMapper * @return */ @IntermediateOp @SuppressWarnings("rawtypes") public ExceptionalStream sortedBy(final Function keyMapper) { assertNotClosed(); final Comparator comparator = new Comparator() { @Override public int compare(T o1, T o2) { return N.compare(keyMapper.apply(o1), keyMapper.apply(o2)); } }; return sorted(comparator); } /** * * @param op * @param sorted * @param cmp * @return */ private ExceptionalStream lazyLoad(final Function op, final boolean sorted, final Comparator cmp) { assertNotClosed(); return newStream(new ExceptionalIterator() { private boolean initialized = false; private T[] aar; private int cursor = 0; private int len; @Override public boolean hasNext() throws E { if (initialized == false) { init(); } return cursor < len; } @Override public T next() throws E { if (initialized == false) { init(); } if (cursor >= len) { throw new NoSuchElementException(); } return aar[cursor++]; } @Override public long count() throws E { if (initialized == false) { init(); } return len - cursor; } @Override public void skip(long n) throws E { checkArgNotNegative(n, "n"); if (initialized == false) { init(); } cursor = n > len - cursor ? len : cursor + (int) n; } private void init() throws E { if (initialized == false) { initialized = true; aar = (T[]) op.apply(ExceptionalStream.this.toArray(false)); len = aar.length; } } }, sorted, cmp, closeHandlers); } @IntermediateOp public ExceptionalStream intersperse(final T delimiter) { assertNotClosed(); return newStream(new ExceptionalIterator() { private final ExceptionalIterator iter = iterator(); private boolean toInsert = false; @Override public boolean hasNext() throws E { return iter.hasNext(); } @Override public T next() throws E { if (hasNext() == false) { throw new NoSuchElementException(); } if (toInsert) { toInsert = false; return delimiter; } else { final T res = iter.next(); toInsert = true; return res; } } }); } @Beta @IntermediateOp public ExceptionalStream, E> indexed() { assertNotClosed(); return map(new Throwables.Function, E>() { private final MutableLong idx = new MutableLong(0); @Override public Indexed apply(T t) { return Indexed.of(t, idx.getAndIncrement()); } }); } /** * * @param * @param * @param b * @param zipFunction * @return */ @IntermediateOp public ExceptionalStream zipWith(final ExceptionalStream b, final Throwables.BiFunction zipFunction) { assertNotClosed(); return zip(this, b, zipFunction); } /** * * @param * @param * @param b * @param valueForNoneA * @param valueForNoneB * @param zipFunction * @return */ @IntermediateOp public ExceptionalStream zipWith(final ExceptionalStream b, final T valueForNoneA, final T2 valueForNoneB, final Throwables.BiFunction zipFunction) { assertNotClosed(); return zip(this, b, valueForNoneA, valueForNoneB, zipFunction); } /** * * @param * @param * @param * @param b * @param c * @param zipFunction * @return */ @IntermediateOp public ExceptionalStream zipWith(final ExceptionalStream b, final ExceptionalStream c, final Throwables.TriFunction zipFunction) { assertNotClosed(); return zip(this, b, c, zipFunction); } /** * * @param * @param * @param * @param b * @param c * @param valueForNoneA * @param valueForNoneB * @param valueForNoneC * @param zipFunction * @return */ @IntermediateOp public ExceptionalStream zipWith(final ExceptionalStream b, final ExceptionalStream c, final T valueForNoneA, final T2 valueForNoneB, final T3 valueForNoneC, final Throwables.TriFunction zipFunction) { assertNotClosed(); return zip(this, b, c, valueForNoneA, valueForNoneB, valueForNoneC, zipFunction); } /** * * @param * @param b * @return */ @IntermediateOp public ExceptionalStream, E> crossJoin(final Collection b) { return crossJoin(b, Fnn. pair()); } /** * * @param * @param * @param b * @param func * @return */ @IntermediateOp public ExceptionalStream crossJoin(final Collection b, final Throwables.BiFunction func) { assertNotClosed(); return flatMap(new Throwables.Function, E>() { @Override public ExceptionalStream apply(final T t) throws E { return ExceptionalStream. of(b).map(new Throwables.Function() { @Override public R apply(U u) throws E { return func.apply(t, u); } }); } }); } /** * * @param * @param * @param b * @param func * @return */ @IntermediateOp public ExceptionalStream crossJoin(final ExceptionalStream b, final Throwables.BiFunction func) { assertNotClosed(); checkArgNotNull(b, "stream"); return flatMap(new Throwables.Function, E>() { private Collection c = null; @Override public ExceptionalStream apply(final T t) throws E { if (c == null) { c = b.toList(); } return ExceptionalStream. of(c).map(new Throwables.Function() { @Override public R apply(U u) throws E { return func.apply(t, u); } }); } }); } /** * * @param * @param * @param b * @param leftKeyMapper * @param rightKeyMapper * @return */ @IntermediateOp public ExceptionalStream, E> innerJoin(final Collection b, final Throwables.Function leftKeyMapper, final Throwables.Function rightKeyMapper) { return innerJoin(b, leftKeyMapper, rightKeyMapper, Fnn. pair()); } /** * * @param * @param * @param * @param b * @param leftKeyMapper * @param rightKeyMapper * @param func * @return */ @IntermediateOp public ExceptionalStream innerJoin(final Collection b, final Throwables.Function leftKeyMapper, final Throwables.Function rightKeyMapper, final Throwables.BiFunction func) { assertNotClosed(); return flatMap(new Throwables.Function, E>() { private ListMultimap rightKeyMap = null; @Override public ExceptionalStream apply(final T t) throws E { if (rightKeyMap == null) { rightKeyMap = ListMultimap.from(b, rightKeyMapper); } return ExceptionalStream. of(rightKeyMap.get(leftKeyMapper.apply(t))).map(new Throwables.Function() { @Override public R apply(U u) throws E { return func.apply(t, u); } }); } }); } /** * * @param * @param b * @param keyMapper * @return */ public ExceptionalStream, E> innerJoin(final Collection b, final Throwables.Function keyMapper) { return innerJoin(b, keyMapper, Fnn. pair()); } /** * * @param * @param * @param b * @param keyMapper * @param func * @return */ @IntermediateOp public ExceptionalStream innerJoin(final Collection b, final Throwables.Function keyMapper, final Throwables.BiFunction func) { return innerJoin(b, keyMapper, keyMapper, func); } /** * * @param * @param * @param * @param b * @param leftKeyMapper * @param rightKeyMapper * @param func * @return */ @IntermediateOp public ExceptionalStream innerJoin(final ExceptionalStream b, final Throwables.Function leftKeyMapper, final Throwables.Function rightKeyMapper, final Throwables.BiFunction func) { assertNotClosed(); checkArgNotNull(b, "stream"); return flatMap(new Throwables.Function, E>() { private ListMultimap rightKeyMap = null; @Override public ExceptionalStream apply(final T t) throws E { if (rightKeyMap == null) { rightKeyMap = (ListMultimap) b.toMultimap(rightKeyMapper); } return ExceptionalStream. of(rightKeyMap.get(leftKeyMapper.apply(t))).map(new Throwables.Function() { @Override public R apply(U u) throws E { return func.apply(t, u); } }); } }); } /** * * @param * @param b * @param predicate * @return */ @IntermediateOp public ExceptionalStream, E> innerJoin(final Collection b, final Throwables.BiPredicate predicate) { assertNotClosed(); return flatMap(new Throwables.Function, E>, E>() { @Override public ExceptionalStream, E> apply(final T t) { return ExceptionalStream. of(b).filter(new Throwables.Predicate() { @Override public boolean test(final U u) throws E { return predicate.test(t, u); } }).map(new Throwables.Function, E>() { @Override public Pair apply(U u) { return Pair.of(t, u); } }); } }); } /** * * @param * @param * @param b * @param leftKeyMapper * @param rightKeyMapper * @return */ @IntermediateOp public ExceptionalStream, E> fullJoin(final Collection b, final Throwables.Function leftKeyMapper, final Throwables.Function rightKeyMapper) { return fullJoin(b, leftKeyMapper, rightKeyMapper, Fnn. pair()); } /** * * @param * @param * @param * @param b * @param leftKeyMapper * @param rightKeyMapper * @param func * @return */ @IntermediateOp public ExceptionalStream fullJoin(final Collection b, final Throwables.Function leftKeyMapper, final Throwables.Function rightKeyMapper, final Throwables.BiFunction func) { assertNotClosed(); final Map joinedRights = new IdentityHashMap<>(); return flatMap(new Throwables.Function, E>() { private ListMultimap rightKeyMap = null; @Override public ExceptionalStream apply(final T t) throws E { if (rightKeyMap == null) { rightKeyMap = ListMultimap.from(b, rightKeyMapper); } final List values = rightKeyMap.get(leftKeyMapper.apply(t)); return N.isNullOrEmpty(values) ? ExceptionalStream. of(func.apply(t, (U) null)) : ExceptionalStream. of(values).map(new Throwables.Function() { @Override public R apply(U u) throws E { joinedRights.put(u, u); return func.apply(t, u); } }); } }).append(ExceptionalStream. of(b).filter(new Throwables.Predicate() { @Override public boolean test(U u) { return joinedRights.containsKey(u) == false; } }).map(new Throwables.Function() { @Override public R apply(U u) throws E { return func.apply((T) null, u); } })); } @SuppressWarnings("rawtypes") private static Throwables.Function HOLDER_VALUE_GETTER = new Throwables.Function, Object, RuntimeException>() { @Override public Object apply(Holder t) { return t.value(); } }; /** * * @param * @param b * @param keyMapper * @return */ public ExceptionalStream, E> fullJoin(final Collection b, final Throwables.Function keyMapper) { return fullJoin(b, keyMapper, Fnn. pair()); } /** * * @param * @param * @param b * @param keyMapper * @param func * @return */ @IntermediateOp public ExceptionalStream fullJoin(final Collection b, final Throwables.Function keyMapper, final Throwables.BiFunction func) { return fullJoin(b, keyMapper, keyMapper, func); } /** * * @param * @param * @param * @param b * @param leftKeyMapper * @param rightKeyMapper * @param func * @return */ @IntermediateOp public ExceptionalStream fullJoin(final ExceptionalStream b, final Throwables.Function leftKeyMapper, final Throwables.Function rightKeyMapper, final Throwables.BiFunction func) { assertNotClosed(); checkArgNotNull(b, "stream"); final Map joinedRights = new IdentityHashMap<>(); final Holder> holder = new Holder<>(); return flatMap(new Throwables.Function, E>() { private List c = null; private ListMultimap rightKeyMap = null; @Override public ExceptionalStream apply(final T t) throws E { if (rightKeyMap == null) { c = (List) b.toList(); rightKeyMap = ListMultimap.from(c, rightKeyMapper); holder.setValue(c); } final List values = rightKeyMap.get(leftKeyMapper.apply(t)); return N.isNullOrEmpty(values) ? ExceptionalStream. of(func.apply(t, (U) null)) : ExceptionalStream. of(values).map(new Throwables.Function() { @Override public R apply(U u) throws E { joinedRights.put(u, u); return func.apply(t, u); } }); } }).append(ExceptionalStream.>, E> of(holder) .flattMap((Throwables.Function>, List, E>) HOLDER_VALUE_GETTER) .filter(new Throwables.Predicate() { @Override public boolean test(U u) { return joinedRights.containsKey(u) == false; } }) .map(new Throwables.Function() { @Override public R apply(U u) throws E { return func.apply((T) null, u); } })); } /** * * @param * @param b * @param predicate * @return */ @IntermediateOp public ExceptionalStream, E> fullJoin(final Collection b, final Throwables.BiPredicate predicate) { assertNotClosed(); final Map joinedRights = new IdentityHashMap<>(); return flatMap(new Throwables.Function, E>, E>() { @Override public ExceptionalStream, E> apply(final T t) { return ExceptionalStream. of(b).filter(new Throwables.Predicate() { @Override public boolean test(final U u) throws E { return predicate.test(t, u); } }).map(new Throwables.Function, E>() { @Override public Pair apply(U u) { joinedRights.put(u, u); return Pair.of(t, u); } }).appendIfEmpty(Pair.of(t, (U) null)); } }).append(ExceptionalStream. of(b).filter(new Throwables.Predicate() { @Override public boolean test(U u) { return joinedRights.containsKey(u) == false; } }).map(new Throwables.Function, E>() { @Override public Pair apply(U u) { return Pair.of((T) null, u); } })); } /** * * @param * @param * @param b * @param leftKeyMapper * @param rightKeyMapper * @return */ @IntermediateOp public ExceptionalStream, E> leftJoin(final Collection b, final Throwables.Function leftKeyMapper, final Throwables.Function rightKeyMapper) { return leftJoin(b, leftKeyMapper, rightKeyMapper, Fnn. pair()); } /** * * @param * @param * @param * @param b * @param leftKeyMapper * @param rightKeyMapper * @param func * @return */ @IntermediateOp public ExceptionalStream leftJoin(final Collection b, final Throwables.Function leftKeyMapper, final Throwables.Function rightKeyMapper, final Throwables.BiFunction func) { assertNotClosed(); return flatMap(new Throwables.Function, E>() { private ListMultimap rightKeyMap = null; @Override public ExceptionalStream apply(final T t) throws E { if (rightKeyMap == null) { rightKeyMap = ListMultimap.from(b, rightKeyMapper); } final List values = rightKeyMap.get(leftKeyMapper.apply(t)); return N.isNullOrEmpty(values) ? ExceptionalStream. of(func.apply(t, (U) null)) : ExceptionalStream. of(values).map(new Throwables.Function() { @Override public R apply(U u) throws E { return func.apply(t, u); } }); } }); } /** * * @param * @param b * @param keyMapper * @return */ public ExceptionalStream, E> leftJoin(final Collection b, final Throwables.Function keyMapper) { return leftJoin(b, keyMapper, Fnn. pair()); } /** * * @param * @param * @param b * @param keyMapper * @param func * @return */ @IntermediateOp public ExceptionalStream leftJoin(final Collection b, final Throwables.Function keyMapper, final Throwables.BiFunction func) { return leftJoin(b, keyMapper, keyMapper, func); } /** * * @param * @param * @param * @param b * @param leftKeyMapper * @param rightKeyMapper * @param func * @return */ @IntermediateOp public ExceptionalStream leftJoin(final ExceptionalStream b, final Throwables.Function leftKeyMapper, final Throwables.Function rightKeyMapper, final Throwables.BiFunction func) { assertNotClosed(); checkArgNotNull(b, "stream"); return flatMap(new Throwables.Function, E>() { private ListMultimap rightKeyMap = null; @Override public ExceptionalStream apply(final T t) throws E { if (rightKeyMap == null) { rightKeyMap = (ListMultimap) b.toMultimap(rightKeyMapper); } final List values = rightKeyMap.get(leftKeyMapper.apply(t)); return N.isNullOrEmpty(values) ? ExceptionalStream. of(func.apply(t, (U) null)) : ExceptionalStream. of(values).map(new Throwables.Function() { @Override public R apply(U u) throws E { return func.apply(t, u); } }); } }); } /** * * @param * @param b * @param predicate * @return */ @IntermediateOp public ExceptionalStream, E> leftJoin(final Collection b, final Throwables.BiPredicate predicate) { assertNotClosed(); return flatMap(new Throwables.Function, E>, E>() { @Override public ExceptionalStream, E> apply(final T t) { return ExceptionalStream. of(b).filter(new Throwables.Predicate() { @Override public boolean test(final U u) throws E { return predicate.test(t, u); } }).map(new Throwables.Function, E>() { @Override public Pair apply(U u) { return Pair.of(t, u); } }).appendIfEmpty(Pair.of(t, (U) null)); } }); } /** * * @param * @param * @param b * @param leftKeyMapper * @param rightKeyMapper * @return */ @IntermediateOp public ExceptionalStream, E> rightJoin(final Collection b, final Throwables.Function leftKeyMapper, final Throwables.Function rightKeyMapper) { return rightJoin(b, leftKeyMapper, rightKeyMapper, Fnn. pair()); } /** * * @param * @param * @param * @param b * @param leftKeyMapper * @param rightKeyMapper * @param func * @return */ @IntermediateOp public ExceptionalStream rightJoin(final Collection b, final Throwables.Function leftKeyMapper, final Throwables.Function rightKeyMapper, final Throwables.BiFunction func) { assertNotClosed(); final Map joinedRights = new IdentityHashMap<>(); return flatMap(new Throwables.Function, E>() { private ListMultimap rightKeyMap = null; @Override public ExceptionalStream apply(final T t) throws E { if (rightKeyMap == null) { rightKeyMap = ListMultimap.from(b, rightKeyMapper); } return ExceptionalStream. of(rightKeyMap.get(leftKeyMapper.apply(t))).map(new Throwables.Function() { @Override public R apply(U u) throws E { joinedRights.put(u, u); return func.apply(t, u); } }); } }).append(ExceptionalStream. of(b).filter(new Throwables.Predicate() { @Override public boolean test(U u) { return joinedRights.containsKey(u) == false; } }).map(new Throwables.Function() { @Override public R apply(U u) throws E { return func.apply((T) null, u); } })); } /** * * @param * @param b * @param keyMapper * @return */ public ExceptionalStream, E> rightJoin(final Collection b, final Throwables.Function keyMapper) { return rightJoin(b, keyMapper, Fnn. pair()); } /** * * @param * @param * @param b * @param keyMapper * @param func * @return */ @IntermediateOp public ExceptionalStream rightJoin(final Collection b, final Throwables.Function keyMapper, final Throwables.BiFunction func) { return rightJoin(b, keyMapper, keyMapper, func); } /** * * @param * @param * @param * @param b * @param leftKeyMapper * @param rightKeyMapper * @param func * @return */ @IntermediateOp public ExceptionalStream rightJoin(final ExceptionalStream b, final Throwables.Function leftKeyMapper, final Throwables.Function rightKeyMapper, final Throwables.BiFunction func) { assertNotClosed(); checkArgNotNull(b, "stream"); final Map joinedRights = new IdentityHashMap<>(); final Holder> holder = new Holder<>(); return flatMap(new Throwables.Function, E>() { private List c = null; private ListMultimap rightKeyMap = null; @Override public ExceptionalStream apply(final T t) throws E { if (rightKeyMap == null) { c = (List) b.toList(); rightKeyMap = ListMultimap.from(c, rightKeyMapper); holder.setValue(c); } return ExceptionalStream. of(rightKeyMap.get(leftKeyMapper.apply(t))).map(new Throwables.Function() { @Override public R apply(U u) throws E { joinedRights.put(u, u); return func.apply(t, u); } }); } }).append(ExceptionalStream.>, E> of(holder) .flattMap((Throwables.Function>, List, E>) HOLDER_VALUE_GETTER) .filter(new Throwables.Predicate() { @Override public boolean test(U u) { return joinedRights.containsKey(u) == false; } }) .map(new Throwables.Function() { @Override public R apply(U u) throws E { return func.apply((T) null, u); } })); } /** * * @param * @param b * @param predicate * @return */ @IntermediateOp public ExceptionalStream, E> rightJoin(final Collection b, final Throwables.BiPredicate predicate) { assertNotClosed(); final Map joinedRights = new IdentityHashMap<>(); return flatMap(new Throwables.Function, E>, E>() { @Override public ExceptionalStream, E> apply(final T t) { return ExceptionalStream. of(b).filter(new Throwables.Predicate() { @Override public boolean test(final U u) throws E { return predicate.test(t, u); } }).map(new Throwables.Function, E>() { @Override public Pair apply(U u) { joinedRights.put(u, u); return Pair.of(t, u); } }); } }).append(ExceptionalStream. of(b).filter(new Throwables.Predicate() { @Override public boolean test(U u) { return joinedRights.containsKey(u) == false; } }).map(new Throwables.Function, E>() { @Override public Pair apply(U u) { return Pair.of((T) null, u); } })); } /** * * @param * @param * @param b * @param leftKeyMapper * @param rightKeyMapper * @return */ @IntermediateOp public ExceptionalStream>, E> groupJoin(final Collection b, final Throwables.Function leftKeyMapper, final Throwables.Function rightKeyMapper) { return groupJoin(b, leftKeyMapper, rightKeyMapper, Fnn., E> pair()); } /** * * @param * @param * @param * @param b * @param leftKeyMapper * @param rightKeyMapper * @param func * @return */ @IntermediateOp public ExceptionalStream groupJoin(final Collection b, final Throwables.Function leftKeyMapper, final Throwables.Function rightKeyMapper, final Throwables.BiFunction, R, ? extends E> func) { assertNotClosed(); final Throwables.Function mapper = new Throwables.Function() { private volatile boolean initialized = false; private volatile Map> map = null; private List val = null; @Override public R apply(T t) throws E { if (initialized == false) { init(); } val = map.get(leftKeyMapper.apply(t)); if (val == null) { return func.apply(t, new ArrayList(0)); } else { return func.apply(t, val); } } private void init() throws E { if (initialized == false) { initialized = true; map = ExceptionalStream. of(b).groupTo(rightKeyMapper); } } }; return map(mapper); } /** * * @param * @param b * @param keyMapper * @return */ public ExceptionalStream>, E> groupJoin(final Collection b, final Throwables.Function keyMapper) { return groupJoin(b, keyMapper, Fnn., E> pair()); } /** * * @param * @param * @param b * @param keyMapper * @param func * @return */ @IntermediateOp public ExceptionalStream groupJoin(final Collection b, final Throwables.Function keyMapper, final Throwables.BiFunction, R, ? extends E> func) { return groupJoin(b, keyMapper, keyMapper, func); } /** * * @param * @param * @param * @param b * @param leftKeyMapper * @param rightKeyMapper * @param func * @return */ @IntermediateOp public ExceptionalStream groupJoin(final ExceptionalStream b, final Throwables.Function leftKeyMapper, final Throwables.Function rightKeyMapper, final Throwables.BiFunction, R, ? extends E> func) { assertNotClosed(); checkArgNotNull(b, "stream"); final Throwables.Function mapper = new Throwables.Function() { private volatile boolean initialized = false; private volatile Map> map = null; private List val = null; @Override public R apply(T t) throws E { if (initialized == false) { init(); } val = map.get(leftKeyMapper.apply(t)); if (val == null) { return func.apply(t, new ArrayList(0)); } else { return func.apply(t, val); } } @SuppressWarnings("rawtypes") private void init() throws E { if (initialized == false) { initialized = true; map = (Map) b.groupTo(rightKeyMapper); } } }; return map(mapper); } /** * * @param * @param * @param b * @param leftKeyMapper * @param rightKeyMapper * @param mergeFunction * @return */ @IntermediateOp public ExceptionalStream, E> groupJoin(final Collection b, final Throwables.Function leftKeyMapper, final Throwables.Function rightKeyMapper, final Throwables.BinaryOperator mergeFunction) { return groupJoin(b, leftKeyMapper, rightKeyMapper, mergeFunction, Fnn. pair()); } /** * * @param * @param * @param * @param b * @param leftKeyMapper * @param rightKeyMapper * @param mergeFunction * @param func * @return */ @IntermediateOp public ExceptionalStream groupJoin(final Collection b, final Throwables.Function leftKeyMapper, final Throwables.Function rightKeyMapper, final Throwables.BinaryOperator mergeFunction, final Throwables.BiFunction func) { assertNotClosed(); final Throwables.Function mapper = new Throwables.Function() { private volatile boolean initialized = false; private volatile Map map = null; private U val = null; @Override public R apply(T t) throws E { if (initialized == false) { init(); } val = map.get(leftKeyMapper.apply(t)); if (val == null) { return func.apply(t, null); } else { return func.apply(t, val); } } private void init() throws E { if (initialized == false) { initialized = true; map = ExceptionalStream. of(b).toMap(rightKeyMapper, Fnn. identity(), mergeFunction); } } }; return map(mapper); } /** * * @param * @param * @param * @param b * @param leftKeyMapper * @param rightKeyMapper * @param mergeFunction * @param func * @return */ @IntermediateOp public ExceptionalStream groupJoin(final ExceptionalStream b, final Throwables.Function leftKeyMapper, final Throwables.Function rightKeyMapper, final Throwables.BinaryOperator mergeFunction, final Throwables.BiFunction func) { assertNotClosed(); checkArgNotNull(b, "stream"); final Throwables.Function mapper = new Throwables.Function() { private volatile boolean initialized = false; private volatile Map map = null; private U val = null; @Override public R apply(T t) throws E { if (initialized == false) { init(); } val = map.get(leftKeyMapper.apply(t)); if (val == null) { return func.apply(t, null); } else { return func.apply(t, val); } } private void init() throws E { if (initialized == false) { initialized = true; map = b.toMap(rightKeyMapper, Fnn. identity(), mergeFunction); } } }; return map(mapper); } /** * * @param * @param * @param * @param * @param b * @param leftKeyMapper * @param rightKeyMapper * @param downstream * @return */ @IntermediateOp public ExceptionalStream, E> groupJoin(final Collection b, final Throwables.Function leftKeyMapper, final Throwables.Function rightKeyMapper, final Collector downstream) { return groupJoin(b, leftKeyMapper, rightKeyMapper, downstream, Fnn. pair()); } /** * * @param * @param * @param * @param * @param * @param b * @param leftKeyMapper * @param rightKeyMapper * @param downstream * @param func * @return */ @IntermediateOp public ExceptionalStream groupJoin(final Collection b, final Throwables.Function leftKeyMapper, final Throwables.Function rightKeyMapper, final Collector downstream, final Throwables.BiFunction func) { assertNotClosed(); final Throwables.Function mapper = new Throwables.Function() { private volatile boolean initialized = false; private volatile Map map = null; private D val = null; @Override public R apply(T t) throws E { if (initialized == false) { init(); } val = map.get(leftKeyMapper.apply(t)); if (val == null) { return func.apply(t, ExceptionalStream. empty().collect(downstream)); } else { return func.apply(t, val); } } private void init() throws E { if (initialized == false) { initialized = true; map = ExceptionalStream. of(b).toMap(rightKeyMapper, Fnn. identity(), downstream); } } }; return map(mapper); } /** * * @param * @param * @param * @param * @param * @param b * @param leftKeyMapper * @param rightKeyMapper * @param downstream * @param func * @return */ @IntermediateOp public ExceptionalStream groupJoin(final ExceptionalStream b, final Throwables.Function leftKeyMapper, final Throwables.Function rightKeyMapper, final Collector downstream, final Throwables.BiFunction func) { assertNotClosed(); checkArgNotNull(b, "stream"); final Throwables.Function mapper = new Throwables.Function() { private volatile boolean initialized = false; private volatile Map map = null; private D val = null; @Override public R apply(T t) throws E { if (initialized == false) { init(); } val = map.get(leftKeyMapper.apply(t)); if (val == null) { return func.apply(t, ExceptionalStream. empty().collect(downstream)); } else { return func.apply(t, val); } } private void init() throws E { if (initialized == false) { initialized = true; map = b.toMap(rightKeyMapper, Fnn. identity(), downstream); } } }; return map(mapper); } /** * * @param * @param action * @throws E the e * @throws E2 the e2 */ @TerminalOp public void forEach(Throwables.Consumer action) throws E, E2 { assertNotClosed(); checkArgNotNull(action, "action"); try { while (elements.hasNext()) { action.accept(elements.next()); } } finally { close(); } } /** * * @param * @param action * @throws E the e * @throws E2 the e2 */ @TerminalOp public void forEachIndexed(Throwables.IndexedConsumer action) throws E, E2 { assertNotClosed(); checkArgNotNull(action, "action"); final MutableInt idx = MutableInt.of(0); try { while (elements.hasNext()) { action.accept(idx.getAndIncrement(), elements.next()); } } finally { close(); } } /** * * @param * @param * @param action * @param onComplete * @throws E the e * @throws E2 the e2 * @throws E3 the e3 */ @TerminalOp public void forEach(final Throwables.Consumer action, final Throwables.Runnable onComplete) throws E, E2, E3 { assertNotClosed(); checkArgNotNull(action, "action"); checkArgNotNull(onComplete, "onComplete"); try { while (elements.hasNext()) { action.accept(elements.next()); } onComplete.run(); } finally { close(); } } /** * * @param * @param * @param * @param flatMapper * @param action * @throws E the e * @throws E2 the e2 * @throws E3 the e3 */ @TerminalOp public void forEach( final Throwables.Function, ? extends E2> flatMapper, final Throwables.BiConsumer action) throws E, E2, E3 { assertNotClosed(); checkArgNotNull(flatMapper, "flatMapper"); checkArgNotNull(action, "action"); Collection c = null; T next = null; try { while (elements.hasNext()) { next = elements.next(); c = flatMapper.apply(next); if (N.notNullOrEmpty(c)) { for (U u : c) { action.accept(next, u); } } } } finally { close(); } } /** * * @param * @param * @param * @param * @param * @param flatMapper * @param flatMapper2 * @param action * @throws E the e * @throws E2 the e2 * @throws E3 the e3 * @throws E4 the e4 */ @TerminalOp public void forEach( final Throwables.Function, ? extends E2> flatMapper, final Throwables.Function, ? extends E3> flatMapper2, final Throwables.TriConsumer action) throws E, E2, E3, E4 { assertNotClosed(); checkArgNotNull(flatMapper, "flatMapper"); checkArgNotNull(flatMapper2, "flatMapper2"); checkArgNotNull(action, "action"); Collection c2 = null; Collection c3 = null; T next = null; try { while (elements.hasNext()) { next = elements.next(); c2 = flatMapper.apply(next); if (N.notNullOrEmpty(c2)) { for (T2 t2 : c2) { c3 = flatMapper2.apply(t2); if (N.notNullOrEmpty(c3)) { for (T3 t3 : c3) { action.accept(next, t2, t3); } } } } } } finally { close(); } } /** * For each pair. * * @param * @param action * @throws E the e * @throws E2 the e2 */ @TerminalOp public void forEachPair(final Throwables.BiConsumer action) throws E, E2 { forEachPair(action, 1); } /** * For each pair. * * @param * @param action * @param increment * @throws E the e * @throws E2 the e2 */ @TerminalOp public void forEachPair(final Throwables.BiConsumer action, final int increment) throws E, E2 { assertNotClosed(); final int windowSize = 2; checkArgPositive(increment, "increment"); try { boolean isFirst = true; T prev = null; while (elements.hasNext()) { if (increment > windowSize && isFirst == false) { int skipNum = increment - windowSize; while (skipNum-- > 0 && elements.hasNext()) { elements.next(); } if (elements.hasNext() == false) { break; } } if (increment == 1) { action.accept(isFirst ? elements.next() : prev, (prev = (elements.hasNext() ? elements.next() : null))); } else { action.accept(elements.next(), elements.hasNext() ? elements.next() : null); } isFirst = false; } } finally { close(); } } /** * For each triple. * * @param * @param action * @throws E the e * @throws E2 the e2 */ @TerminalOp public void forEachTriple(final Throwables.TriConsumer action) throws E, E2 { forEachTriple(action, 1); } /** * For each triple. * * @param * @param action * @param increment * @throws E the e * @throws E2 the e2 */ @TerminalOp public void forEachTriple(final Throwables.TriConsumer action, final int increment) throws E, E2 { assertNotClosed(); final int windowSize = 3; checkArgPositive(increment, "increment"); try { boolean isFirst = true; T prev = null; T prev2 = null; while (elements.hasNext()) { if (increment > windowSize && isFirst == false) { int skipNum = increment - windowSize; while (skipNum-- > 0 && elements.hasNext()) { elements.next(); } if (elements.hasNext() == false) { break; } } if (increment == 1) { action.accept(isFirst ? elements.next() : prev2, (prev2 = (isFirst ? (elements.hasNext() ? elements.next() : null) : prev)), (prev = (elements.hasNext() ? elements.next() : null))); } else if (increment == 2) { action.accept(isFirst ? elements.next() : prev, elements.hasNext() ? elements.next() : null, (prev = (elements.hasNext() ? elements.next() : null))); } else { action.accept(elements.next(), elements.hasNext() ? elements.next() : null, elements.hasNext() ? elements.next() : null); } isFirst = false; } } finally { close(); } } /** * * @param comparator * @return * @throws E the e */ @TerminalOp public Optional min(Comparator comparator) throws E { assertNotClosed(); try { if (elements.hasNext() == false) { return Optional.empty(); } else if (sorted && isSameComparator(comparator, comparator)) { return Optional.of(elements.next()); } comparator = comparator == null ? Comparators.NATURAL_ORDER : comparator; T candidate = elements.next(); T next = null; while (elements.hasNext()) { next = elements.next(); if (comparator.compare(next, candidate) < 0) { candidate = next; } } return Optional.of(candidate); } finally { close(); } } /** * * @param keyMapper * @return * @throws E the e */ @TerminalOp @SuppressWarnings("rawtypes") public Optional minBy(final Function keyMapper) throws E { assertNotClosed(); checkArgNotNull(keyMapper, "keyMapper"); try { final Comparator comparator = Fn.comparingBy(keyMapper); return min(comparator); } finally { close(); } } /** * * @param comparator * @return * @throws E the e */ @TerminalOp public Optional max(Comparator comparator) throws E { assertNotClosed(); try { if (elements.hasNext() == false) { return Optional.empty(); } else if (sorted && isSameComparator(comparator, comparator)) { T next = null; while (elements.hasNext()) { next = elements.next(); } return Optional.of(next); } comparator = comparator == null ? Comparators.NATURAL_ORDER : comparator; T candidate = elements.next(); T next = null; while (elements.hasNext()) { next = elements.next(); if (comparator.compare(next, candidate) > 0) { candidate = next; } } return Optional.of(candidate); } finally { close(); } } /** * * @param keyMapper * @return * @throws E the e */ @TerminalOp @SuppressWarnings("rawtypes") public Optional maxBy(final Function keyMapper) throws E { assertNotClosed(); checkArgNotNull(keyMapper, "keyMapper"); try { final Comparator comparator = Fn.comparingBy(keyMapper); return max(comparator); } finally { close(); } } /** * * @param predicate * @return true, if successful * @throws E the e */ @TerminalOp public boolean anyMatch(final Throwables.Predicate predicate) throws E { assertNotClosed(); try { while (elements.hasNext()) { if (predicate.test(elements.next())) { return true; } } return false; } finally { close(); } } /** * * @param predicate * @return true, if successful * @throws E the e */ @TerminalOp public boolean allMatch(final Throwables.Predicate predicate) throws E { assertNotClosed(); try { while (elements.hasNext()) { if (predicate.test(elements.next()) == false) { return false; } } return true; } finally { close(); } } /** * * @param predicate * @return true, if successful * @throws E the e */ @TerminalOp public boolean noneMatch(final Throwables.Predicate predicate) throws E { assertNotClosed(); try { while (elements.hasNext()) { if (predicate.test(elements.next())) { return false; } } return true; } finally { close(); } } /** * * @param atLeast * @param atMost * @param predicate * @return * @throws E */ @TerminalOp public boolean nMatch(final long atLeast, final long atMost, final Throwables.Predicate predicate) throws E { assertNotClosed(); checkArgNotNegative(atLeast, "atLeast"); checkArgNotNegative(atMost, "atMost"); checkArgument(atLeast <= atMost, "'atLeast' must be <= 'atMost'"); long cnt = 0; try { while (elements.hasNext()) { if (predicate.test(elements.next())) { if (++cnt > atMost) { return false; } } } } finally { close(); } return cnt >= atLeast && cnt <= atMost; } @TerminalOp @SafeVarargs public final boolean containsAll(final T... a) throws E { assertNotClosed(); try { if (N.isNullOrEmpty(a)) { return true; } else if (a.length == 1 || (a.length == 2 && N.equals(a[0], a[1]))) { return anyMatch(Fnn. pp(Fn. equal(a[0]))); } else if (a.length == 2) { return filter(new Throwables.Predicate() { private final T val1 = a[0]; private final T val2 = a[1]; @Override public boolean test(T t) { return N.equals(t, val1) || N.equals(t, val2); } }).distinct().limit(2).count() == 2; } else { return containsAll(N.asSet(a)); } } finally { close(); } } @TerminalOp public boolean containsAll(final Collection c) throws E { assertNotClosed(); try { if (N.isNullOrEmpty(c)) { return true; } else if (c.size() == 1) { final T val = c instanceof List ? ((List) c).get(0) : c.iterator().next(); return anyMatch(Fnn. pp(Fn. equal(val))); } else { final Set set = c instanceof Set ? (Set) c : N.newHashSet(c); final int distinctCount = set.size(); return filter(new Throwables.Predicate() { @Override public boolean test(T t) { return set.contains(t); } }).distinct().limit(distinctCount).count() == distinctCount; } } finally { close(); } } @TerminalOp @SafeVarargs public final boolean containsAny(final T... a) throws E { assertNotClosed(); try { if (N.isNullOrEmpty(a)) { return false; } else if (a.length == 1 || (a.length == 2 && N.equals(a[0], a[1]))) { return anyMatch(Fnn. pp(Fn. equal(a[0]))); } else if (a.length == 2) { return anyMatch(new Throwables.Predicate() { private final T val1 = a[0]; private final T val2 = a[1]; @Override public boolean test(T t) { return N.equals(t, val1) || N.equals(t, val2); } }); } else { final Set set = N.asSet(a); return anyMatch(new Throwables.Predicate() { @Override public boolean test(T t) { return set.contains(t); } }); } } finally { close(); } } @TerminalOp public boolean containsAny(final Collection c) throws E { assertNotClosed(); try { if (N.isNullOrEmpty(c)) { return false; } else if (c.size() == 1) { final T val = c instanceof List ? ((List) c).get(0) : c.iterator().next(); return anyMatch(Fnn. pp(Fn. equal(val))); } else { final Set set = c instanceof Set ? (Set) c : N.newHashSet(c); return anyMatch(new Throwables.Predicate() { @Override public boolean test(T t) { return set.contains(t); } }); } } finally { close(); } } /** * * @return * @throws E the e */ @TerminalOp public Optional first() throws E { assertNotClosed(); try { if (elements.hasNext() == false) { return Optional.empty(); } return Optional.of(elements.next()); } finally { close(); } } /** * * @return * @throws E the e */ @TerminalOp public Optional last() throws E { assertNotClosed(); try { if (elements.hasNext() == false) { return Optional.empty(); } T next = elements.next(); while (elements.hasNext()) { next = elements.next(); } return Optional.of(next); } finally { close(); } } /** * * @return * @throws E the e */ @TerminalOp public Object[] toArray() throws E { return toArray(true); } private Object[] toArray(final boolean closeStream) throws E { assertNotClosed(); try { return toList().toArray(); } finally { if (closeStream) { close(); } } } /** * * @param * @param generator * @return * @throws E the e */ @TerminalOp public A[] toArray(IntFunction generator) throws E { assertNotClosed(); checkArgNotNull(generator, "generator"); try { final List list = toList(); return list.toArray(generator.apply(list.size())); } finally { close(); } } /** * * @return * @throws E the e */ @TerminalOp public List toList() throws E { assertNotClosed(); try { final List result = new ArrayList<>(); while (elements.hasNext()) { result.add(elements.next()); } return result; } finally { close(); } } /** * * @return * @throws E the e */ @TerminalOp public Set toSet() throws E { assertNotClosed(); try { final Set result = N.newHashSet(); while (elements.hasNext()) { result.add(elements.next()); } return result; } finally { close(); } } /** * * @return * @throws E the e */ @TerminalOp public ImmutableList toImmutableList() throws E { return ImmutableList.of(toList()); } /** * * @return * @throws E the e */ @TerminalOp public ImmutableSet toImmutableSet() throws E { return ImmutableSet.of(toSet()); } /** * * @param * @param supplier * @return * @throws E the e */ @TerminalOp public > C toCollection(final Supplier supplier) throws E { assertNotClosed(); checkArgNotNull(supplier, "supplier"); try { final C result = supplier.get(); while (elements.hasNext()) { result.add(elements.next()); } return result; } finally { close(); } } /** * * @param the key type * @param the value type * @param keyMapper * @param valueMapper * @return * @throws E the e * @throws IllegalStateException if there are duplicated keys. * @see {@link Fn.Fnn#throwingMerger()} * @see {@link Fn.Fnn#replacingMerger()} * @see {@link Fn.Fnn#ignoringMerger()} */ @TerminalOp public Map toMap(final Throwables.Function keyMapper, final Throwables.Function valueMapper) throws E, IllegalStateException { return toMap(keyMapper, valueMapper, Suppliers. ofMap()); } /** * * @param the key type * @param the value type * @param * @param keyMapper * @param valueMapper * @param mapFactory * @return * @throws E the e * @throws IllegalStateException if there are duplicated keys. * @see {@link Fn.Fnn#throwingMerger()} * @see {@link Fn.Fnn#replacingMerger()} * @see {@link Fn.Fnn#ignoringMerger()} */ @TerminalOp public > M toMap(final Throwables.Function keyMapper, final Throwables.Function valueMapper, final Supplier mapFactory) throws E, IllegalStateException { return toMap(keyMapper, valueMapper, Fnn. throwingMerger(), mapFactory); } /** * * @param the key type * @param the value type * @param keyMapper * @param valueMapper * @param mergeFunction * @return * @throws E the e * @see {@link Fn.Fnn#throwingMerger()} * @see {@link Fn.Fnn#replacingMerger()} * @see {@link Fn.Fnn#ignoringMerger()} */ @TerminalOp public Map toMap(final Throwables.Function keyMapper, final Throwables.Function valueMapper, final Throwables.BinaryOperator mergeFunction) throws E { return toMap(keyMapper, valueMapper, mergeFunction, Suppliers. ofMap()); } /** * * @param the key type * @param the value type * @param * @param keyMapper * @param valueMapper * @param mergeFunction * @param mapFactory * @return * @throws E the e * @see {@link Fn.Fnn#throwingMerger()} * @see {@link Fn.Fnn#replacingMerger()} * @see {@link Fn.Fnn#ignoringMerger()} */ @TerminalOp public > M toMap(final Throwables.Function keyMapper, final Throwables.Function valueMapper, final Throwables.BinaryOperator mergeFunction, final Supplier mapFactory) throws E { assertNotClosed(); checkArgNotNull(keyMapper, "keyMapper"); checkArgNotNull(valueMapper, "valueMapper"); checkArgNotNull(mergeFunction, "mergeFunction"); checkArgNotNull(mapFactory, "mapFactory"); try { final M result = mapFactory.get(); T next = null; while (elements.hasNext()) { next = elements.next(); Maps.merge(result, keyMapper.apply(next), valueMapper.apply(next), mergeFunction); } return result; } finally { close(); } } /** * * @param the key type * @param * @param * @param keyMapper * @param downstream * @return * @throws E the e */ @TerminalOp public Map toMap(final Throwables.Function keyMapper, final Collector downstream) throws E { return toMap(keyMapper, downstream, Suppliers. ofMap()); } /** * * @param the key type * @param * @param * @param * @param keyMapper * @param downstream * @param mapFactory * @return * @throws E the e */ @TerminalOp public > M toMap(final Throwables.Function keyMapper, final Collector downstream, final Supplier mapFactory) throws E { return toMap(keyMapper, Fnn. identity(), downstream, mapFactory); } /** * * @param the key type * @param the value type * @param * @param * @param keyMapper * @param valueMapper * @param downstream * @return * @throws E the e */ @TerminalOp public Map toMap(final Throwables.Function keyMapper, final Throwables.Function valueMapper, final Collector downstream) throws E { return toMap(keyMapper, valueMapper, downstream, Suppliers. ofMap()); } /** * * @param the key type * @param the value type * @param * @param * @param * @param keyMapper * @param valueMapper * @param downstream * @param mapFactory * @return * @throws E the e */ @TerminalOp public > M toMap(final Throwables.Function keyMapper, final Throwables.Function valueMapper, final Collector downstream, final Supplier mapFactory) throws E { assertNotClosed(); checkArgNotNull(keyMapper, "keyMapper"); checkArgNotNull(valueMapper, "valueMapper"); checkArgNotNull(downstream, "downstream"); checkArgNotNull(mapFactory, "mapFactory"); try { final Supplier downstreamSupplier = downstream.supplier(); final BiConsumer downstreamAccumulator = downstream.accumulator(); final Function downstreamFinisher = downstream.finisher(); final M result = mapFactory.get(); final Map tmp = (Map) result; T next = null; K key = null; A container = null; while (elements.hasNext()) { next = elements.next(); key = keyMapper.apply(next); container = tmp.get(key); if (container == null) { container = downstreamSupplier.get(); tmp.put(key, container); } downstreamAccumulator.accept(container, valueMapper.apply(next)); } for (Map.Entry entry : result.entrySet()) { entry.setValue(downstreamFinisher.apply((A) entry.getValue())); } return result; } finally { close(); } } /** * * @param the key type * @param keyMapper * @return * @throws E the e * @see Collectors#groupingBy(Function) */ @TerminalOp public Map> groupTo(Throwables.Function keyMapper) throws E { return groupTo(keyMapper, Suppliers.> ofMap()); } /** * * @param the key type * @param * @param keyMapper * @param mapFactory * @return * @throws E the e * @see Collectors#groupingBy(Function, Supplier) */ @TerminalOp public >> M groupTo(final Throwables.Function keyMapper, final Supplier mapFactory) throws E { final Throwables.Function valueMapper = Fnn.identity(); return groupTo(keyMapper, valueMapper, mapFactory); } /** * * @param the key type * @param the value type * @param keyMapper * @param valueMapper * @return * @throws E the e */ @TerminalOp public Map> groupTo(Throwables.Function keyMapper, Throwables.Function valueMapper) throws E { return groupTo(keyMapper, valueMapper, Suppliers.> ofMap()); } /** * * @param the key type * @param the value type * @param * @param keyMapper * @param valueMapper * @param mapFactory * @return * @throws E the e * @see Collectors#toMultimap(Function, Function, Supplier) */ @TerminalOp public >> M groupTo(Throwables.Function keyMapper, Throwables.Function valueMapper, Supplier mapFactory) throws E { assertNotClosed(); checkArgNotNull(keyMapper, "keyMapper"); checkArgNotNull(valueMapper, "valueMapper"); checkArgNotNull(mapFactory, "mapFactory"); try { final M result = mapFactory.get(); T next = null; K key = null; while (elements.hasNext()) { next = elements.next(); key = keyMapper.apply(next); if (result.containsKey(key) == false) { result.put(key, new ArrayList()); } result.get(key).add(valueMapper.apply(next)); } return result; } finally { close(); } } @TerminalOp public ListMultimap toMultimap(final Throwables.Function keyMapper) throws E { return toMultimap(keyMapper, Suppliers. ofListMultimap()); } @TerminalOp public , M extends Multimap> M toMultimap(final Throwables.Function keyMapper, Supplier mapFactory) throws E { final Throwables.Function valueMapper = Fnn.identity(); return toMultimap(keyMapper, valueMapper, mapFactory); } @TerminalOp public ListMultimap toMultimap(final Throwables.Function keyMapper, final Throwables.Function valueMapper) throws E { return toMultimap(keyMapper, valueMapper, Suppliers. ofListMultimap()); } @TerminalOp public , M extends Multimap> M toMultimap(final Throwables.Function keyMapper, final Throwables.Function valueMapper, Supplier mapFactory) throws E { assertNotClosed(); checkArgNotNull(keyMapper, "keyMapper"); checkArgNotNull(valueMapper, "valueMapper"); checkArgNotNull(mapFactory, "mapFactory"); try { final M result = mapFactory.get(); T next = null; while (elements.hasNext()) { next = elements.next(); result.put(keyMapper.apply(next), valueMapper.apply(next)); } return result; } finally { close(); } } @TerminalOp public Multiset toMultiset() throws E { return toMultiset(Suppliers. ofMultiset()); } @TerminalOp public Multiset toMultiset(Supplier> supplier) throws E { assertNotClosed(); checkArgNotNull(supplier, "supplier"); try { final Multiset result = supplier.get(); while (elements.hasNext()) { result.add(elements.next()); } return result; } finally { close(); } } /** * The first row will be used as column names if its type is array or list, * or obtain the column names from first row if its type is entity or map. * * @return * @throws E * @see {@link N#newDataSet(Collection)} */ @TerminalOp public DataSet toDataSet() throws E { return N.newDataSet(toList()); } /** * If the specified {@code columnNames} is null or empty, the first row will be used as column names if its type is array or list, * or obtain the column names from first row if its type is entity or map. * * * @param columnNames * @return * @throws E * @see {@link N#newDataSet(Collection, Collection)} */ @TerminalOp public DataSet toDataSet(List columnNames) throws E { return N.newDataSet(columnNames, toList()); } /** * * @return * @throws E the e */ @TerminalOp public long count() throws E { assertNotClosed(); try { return elements.count(); } finally { close(); } } /** * * @return * @throws DuplicatedResultException if there are more than one elements. * @throws E the e */ @TerminalOp public Optional onlyOne() throws DuplicatedResultException, E { assertNotClosed(); try { Optional result = Optional.empty(); if (elements.hasNext()) { result = Optional.of(elements.next()); if (elements.hasNext()) { throw new DuplicatedResultException("There are at least two elements: " + Strings.concat(result.get(), ", ", elements.next())); } } return result; } finally { close(); } } /** * * @param func * @return * @throws E the e */ @TerminalOp public OptionalLong sumInt(Throwables.ToIntFunction func) throws E { assertNotClosed(); try { if (elements.hasNext() == false) { return OptionalLong.empty(); } long sum = 0; while (elements.hasNext()) { sum += func.applyAsInt(elements.next()); } return OptionalLong.of(sum); } finally { close(); } } /** * * @param func * @return * @throws E the e */ @TerminalOp public OptionalLong sumLong(Throwables.ToLongFunction func) throws E { assertNotClosed(); try { if (elements.hasNext() == false) { return OptionalLong.empty(); } long sum = 0; while (elements.hasNext()) { sum += func.applyAsLong(elements.next()); } return OptionalLong.of(sum); } finally { close(); } } /** * * @param func * @return * @throws E the e */ @TerminalOp public OptionalDouble sumDouble(Throwables.ToDoubleFunction func) throws E { assertNotClosed(); try { if (elements.hasNext() == false) { return OptionalDouble.empty(); } final KahanSummation summation = new KahanSummation(); while (elements.hasNext()) { summation.add(func.applyAsDouble(elements.next())); } return OptionalDouble.of(summation.sum()); } finally { close(); } } /** * * @param func * @return * @throws E the e */ @TerminalOp public OptionalDouble averageInt(Throwables.ToIntFunction func) throws E { assertNotClosed(); try { if (elements.hasNext() == false) { return OptionalDouble.empty(); } long sum = 0; long count = 0; while (elements.hasNext()) { sum += func.applyAsInt(elements.next()); count++; } return OptionalDouble.of(((double) sum) / count); } finally { close(); } } /** * * @param func * @return * @throws E the e */ @TerminalOp public OptionalDouble averageLong(Throwables.ToLongFunction func) throws E { assertNotClosed(); try { if (elements.hasNext() == false) { return OptionalDouble.empty(); } long sum = 0; long count = 0; while (elements.hasNext()) { sum += func.applyAsLong(elements.next()); count++; } return OptionalDouble.of(((double) sum) / count); } finally { close(); } } /** * * @param func * @return * @throws E the e */ @TerminalOp public OptionalDouble averageDouble(Throwables.ToDoubleFunction func) throws E { assertNotClosed(); try { if (elements.hasNext() == false) { return OptionalDouble.empty(); } final KahanSummation summation = new KahanSummation(); while (elements.hasNext()) { summation.add(func.applyAsDouble(elements.next())); } return summation.average(); } finally { close(); } } /** * * @param * @param accumulator * @return * @throws E the e * @throws E2 the e2 */ @TerminalOp public Optional reduce(Throwables.BinaryOperator accumulator) throws E, E2 { assertNotClosed(); checkArgNotNull(accumulator, "accumulator"); try { if (elements.hasNext() == false) { return Optional.empty(); } T result = elements.next(); while (elements.hasNext()) { result = accumulator.apply(result, elements.next()); } return Optional.of(result); } finally { close(); } } /** * * @param * @param * @param identity * @param accumulator * @return * @throws E the e * @throws E2 the e2 */ @TerminalOp public U reduce(final U identity, final Throwables.BiFunction accumulator) throws E, E2 { assertNotClosed(); checkArgNotNull(accumulator, "accumulator"); try { U result = identity; while (elements.hasNext()) { result = accumulator.apply(result, elements.next()); } return result; } finally { close(); } } /** * * @param * @param * @param * @param supplier * @param accumulator * @return * @throws E the e * @throws E2 the e2 * @throws E3 the e3 */ @TerminalOp public R collect(final Throwables.Supplier supplier, final Throwables.BiConsumer accumulator) throws E, E2, E3 { assertNotClosed(); checkArgNotNull(supplier, "supplier"); checkArgNotNull(accumulator, "accumulator"); try { final R result = supplier.get(); while (elements.hasNext()) { accumulator.accept(result, elements.next()); } return result; } finally { close(); } } /** * * @param * @param * @param * @param * @param * @param supplier * @param accumulator * @param finisher * @return * @throws E the e * @throws E2 the e2 * @throws E3 the e3 * @throws E4 the e4 */ @TerminalOp public RR collect(final Throwables.Supplier supplier, final Throwables.BiConsumer accumulator, final Throwables.Function finisher) throws E, E2, E3, E4 { assertNotClosed(); checkArgNotNull(supplier, "supplier"); checkArgNotNull(accumulator, "accumulator"); checkArgNotNull(finisher, "finisher"); try { final R result = supplier.get(); while (elements.hasNext()) { accumulator.accept(result, elements.next()); } return finisher.apply(result); } finally { close(); } } /** * * @param * @param * @param collector * @return * @throws E the e */ @TerminalOp public R collect(final Collector collector) throws E { assertNotClosed(); checkArgNotNull(collector, "collector"); try { final A container = collector.supplier().get(); final BiConsumer accumulator = collector.accumulator(); while (elements.hasNext()) { accumulator.accept(container, elements.next()); } return collector.finisher().apply(container); } finally { close(); } } /** * Collect and then. * * @param * @param * @param * @param * @param collector * @param func * @return * @throws E the e * @throws E2 the e2 */ @TerminalOp public RR collectAndThen(final Collector collector, final Throwables.Function func) throws E, E2 { assertNotClosed(); checkArgNotNull(collector, "collector"); checkArgNotNull(func, "func"); return func.apply(collect(collector)); } @TerminalOp public String join(final CharSequence delimiter) throws E { return join(delimiter, "", ""); } @TerminalOp public String join(CharSequence delimiter, CharSequence prefix, CharSequence suffix) throws E { assertNotClosed(); try { final Joiner joiner = Joiner.with(delimiter, prefix, suffix).reuseCachedBuffer(); while (elements.hasNext()) { joiner.append(elements.next()); } return joiner.toString(); } finally { close(); } } @TerminalOp @Beta public void println() throws E { N.println(join(", ", "[", "]")); } /** * @param closeHandler * @return */ @IntermediateOp public ExceptionalStream onClose(final Throwables.Runnable closeHandler) { assertNotClosed(); checkArgNotNull(closeHandler, "closeHandler"); final Deque> newCloseHandlers = new ArrayDeque<>(N.size(closeHandlers) + 1); newCloseHandlers.add(new Throwables.Runnable() { private volatile boolean isClosed = false; @Override public void run() throws E { if (isClosed) { return; } isClosed = true; closeHandler.run(); } }); if (N.notNullOrEmpty(this.closeHandlers)) { newCloseHandlers.addAll(this.closeHandlers); } return newStream(elements, newCloseHandlers); } /** * * @throws E the e */ @TerminalOp @Override public synchronized void close() { if (isClosed) { return; } if (N.isNullOrEmpty(closeHandlers)) { isClosed = true; return; } // // Only mark the stream closed if closeHandlers are not empty. // if (isClosed || N.isNullOrEmpty(closeHandlers)) { // return; // } logger.info("Closing ExceptionalStream"); isClosed = true; close(closeHandlers); } static void close(final Deque> closeHandlers) { Throwable ex = null; for (Throwables.Runnable closeHandler : closeHandlers) { try { closeHandler.run(); } catch (Exception e) { if (ex == null) { ex = e; } else { ex.addSuppressed(e); } } } if (ex != null) { throw N.toRuntimeException(ex); } } ExceptionalIterator iterator() { return elements; } /** * Assert not closed. */ void assertNotClosed() { if (isClosed) { throw new IllegalStateException("This stream has been closed"); } } /** * Check arg positive. * * @param arg * @param argNameOrErrorMsg * @return */ private int checkArgPositive(final int arg, final String argNameOrErrorMsg) { if (arg <= 0) { try { N.checkArgPositive(arg, argNameOrErrorMsg); } finally { try { close(); } catch (Exception e) { throw N.toRuntimeException(e); } } } return arg; } /** * Check arg not negative. * * @param arg * @param argNameOrErrorMsg * @return */ private long checkArgNotNegative(final long arg, final String argNameOrErrorMsg) { if (arg < 0) { try { N.checkArgNotNegative(arg, argNameOrErrorMsg); } finally { try { close(); } catch (Exception e) { throw N.toRuntimeException(e); } } } return arg; } /** * Check arg not null. * * @param * @param obj * @param errorMessage * @return */ private ARG checkArgNotNull(final ARG obj, final String errorMessage) { if (obj == null) { try { N.checkArgNotNull(obj, errorMessage); } finally { try { close(); } catch (Exception e) { throw N.toRuntimeException(e); } } } return obj; } /** * * @param b * @param errorMessage */ private void checkArgument(boolean b, String errorMessage) { if (!b) { try { N.checkArgument(b, errorMessage); } finally { try { close(); } catch (Exception e) { throw N.toRuntimeException(e); } } } } /** * * @param b * @param errorMessageTemplate * @param p1 * @param p2 */ private void checkArgument(boolean b, String errorMessageTemplate, int p1, int p2) { if (!b) { try { N.checkArgument(b, errorMessageTemplate, p1, p2); } finally { try { close(); } catch (Exception e) { throw N.toRuntimeException(e); } } } } /** * * @param * @param * @param iter * @return */ static ExceptionalStream newStream(final ExceptionalIterator iter) { return new ExceptionalStream<>(iter, null); } /** * * @param * @param * @param iter * @param closeHandlers * @return */ static ExceptionalStream newStream(final ExceptionalIterator iter, final Deque> closeHandlers) { return new ExceptionalStream<>(iter, closeHandlers); } /** * * @param * @param * @param iter * @param sorted * @param comparator * @param closeHandlers * @return */ static ExceptionalStream newStream(final ExceptionalIterator iter, final boolean sorted, final Comparator comparator, final Deque> closeHandlers) { return new ExceptionalStream<>(iter, sorted, comparator, closeHandlers); } /** * * @param obj * @return */ static Object hashKey(Object obj) { return obj == null || obj.getClass().isArray() == false ? obj : Wrapper.of(obj); } /** * Checks if is same comparator. * * @param a * @param b * @return true, if is same comparator */ static boolean isSameComparator(Comparator a, Comparator b) { return a == b || (a == null && b == Comparators.NATURAL_ORDER) || (b == null && a == Comparators.NATURAL_ORDER); } /** * The Class ExceptionalIterator. * * @param * @param */ static abstract class ExceptionalIterator { /** The Constant EMPTY. */ @SuppressWarnings("rawtypes") private static final ExceptionalIterator EMPTY = new ExceptionalIterator() { @Override public boolean hasNext() throws Exception { return false; } @Override public Object next() throws Exception { throw new NoSuchElementException(); } }; public static ExceptionalIterator wrap(final Iterator iter) { if (iter == null) { return EMPTY; } return new ExceptionalIterator() { @Override public boolean hasNext() throws E { return iter.hasNext(); } @Override public T next() throws E { return iter.next(); } }; } /** * Lazy evaluation. * * @param * @param * @param iteratorSupplier * @return */ public static ExceptionalIterator of(final Throwables.Supplier, E> iteratorSupplier) { N.checkArgNotNull(iteratorSupplier, "iteratorSupplier"); return new ExceptionalIterator() { private ExceptionalIterator iter = null; private boolean isInitialized = false; @Override public boolean hasNext() throws E { if (isInitialized == false) { init(); } return iter.hasNext(); } @Override public T next() throws E { if (isInitialized == false) { init(); } return iter.next(); } @Override public void skip(long n) throws E { N.checkArgNotNegative(n, "n"); if (isInitialized == false) { init(); } iter.skip(n); } @Override public long count() throws E { if (isInitialized == false) { init(); } return iter.count(); } @Override public void close() throws E { if (isInitialized == false) { init(); } iter.close(); } private void init() throws E { if (isInitialized == false) { isInitialized = true; iter = iteratorSupplier.get(); } } }; } /** * Lazy evaluation. * * @param * @param * @param arraySupplier * @return */ public static ExceptionalIterator oF(final Throwables.Supplier arraySupplier) { N.checkArgNotNull(arraySupplier, "arraySupplier"); return new ExceptionalIterator() { private T[] a; private int len; private int position = 0; private boolean isInitialized = false; @Override public boolean hasNext() throws E { if (isInitialized == false) { init(); } return position < len; } @Override public T next() throws E { if (isInitialized == false) { init(); } if (position >= len) { throw new NoSuchElementException(); } return a[position++]; } @Override public long count() throws E { if (isInitialized == false) { init(); } return len - position; } @Override public void skip(long n) throws E { N.checkArgNotNegative(n, "n"); if (isInitialized == false) { init(); } if (n > len - position) { position = len; } else { position += n; } } private void init() throws E { if (isInitialized == false) { isInitialized = true; a = arraySupplier.get(); len = N.len(a); } } }; } /** * Checks for next. * * @return true, if successful * @throws E the e */ public abstract boolean hasNext() throws E; /** * * @return * @throws E the e */ public abstract T next() throws E; /** * * @param n * @throws E the e */ public void skip(long n) throws E { N.checkArgNotNegative(n, "n"); while (n-- > 0 && hasNext()) { next(); } } /** * * @return * @throws E the e */ public long count() throws E { long result = 0; while (hasNext()) { next(); result++; } return result; } /** * * @throws E the e */ public void close() throws E { // Nothing to do by default. } } public static final class StreamE extends ExceptionalStream { StreamE(ExceptionalIterator iter, boolean sorted, Comparator comparator, Deque> closeHandlers) { super(iter, sorted, comparator, closeHandlers); } } /** * Mostly it's for android. * */ public static final class StreamR { private StreamR() { // singleton for utility class. } public static ExceptionalStream empty() { return ExceptionalStream. empty(); } public static ExceptionalStream just(final T e) { return ExceptionalStream. just(e); } public static ExceptionalStream ofNullable(final T e) { return ExceptionalStream. ofNullable(e); } public static ExceptionalStream of(final T... a) { return ExceptionalStream. of(a); } public static ExceptionalStream of(final Collection c) { return ExceptionalStream. of(c); } public static ExceptionalStream of(final Iterator iter) { return ExceptionalStream. of(iter); } public static ExceptionalStream of(final Iterable iterable) { return ExceptionalStream. of(iterable); } public static ExceptionalStream, RuntimeException> of(final Map m) { return ExceptionalStream. of(m); } public static ExceptionalStream of(final int[] a) { return ExceptionalStream. of(a); } public static ExceptionalStream of(final long[] a) { return ExceptionalStream. of(a); } public static ExceptionalStream of(final double[] a) { return ExceptionalStream. of(a); } public static ExceptionalStream of(final Throwables.Supplier, RuntimeException> supplier) { return ExceptionalStream. of(supplier); } public static ExceptionalStream from( final Throwables.Supplier, RuntimeException> supplier) { return ExceptionalStream. from(supplier); } public static ExceptionalStream ofKeys(final Map map) { return ExceptionalStream. ofKeys(map); } public static ExceptionalStream ofValues(final Map map) { return ExceptionalStream. ofValues(map); } public static ExceptionalStream iterate(final Throwables.BooleanSupplier hasNext, final Throwables.Supplier next) { return ExceptionalStream. iterate(hasNext, next); } public static ExceptionalStream iterate(final T init, final Throwables.BooleanSupplier hasNext, final Throwables.UnaryOperator f) { return ExceptionalStream. iterate(init, hasNext, f); } public static ExceptionalStream iterate(final T init, final Throwables.Predicate hasNext, final Throwables.UnaryOperator f) { return ExceptionalStream. iterate(init, hasNext, f); } public static ExceptionalStream iterate(final T init, final Throwables.UnaryOperator f) { return ExceptionalStream. iterate(init, f); } public static ExceptionalStream generate(final Throwables.Supplier supplier) { return ExceptionalStream. generate(supplier); } public static ExceptionalStream repeat(final T element, final long n) { return ExceptionalStream. repeat(element, n); } } }