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

com.landawn.abacus.util.stream.Stream 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: 5.2.4
Show newest version
/*
 * Copyright (C) 2016, 2017, 2018, 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.stream;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.security.SecureRandom;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Deque;
import java.util.Enumeration;
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 java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.BinaryOperator;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import java.util.function.DoubleConsumer;
import java.util.function.Function;
import java.util.function.IntConsumer;
import java.util.function.IntFunction;
import java.util.function.LongConsumer;
import java.util.function.LongFunction;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.function.ToDoubleFunction;
import java.util.function.ToIntFunction;
import java.util.function.ToLongFunction;
import java.util.function.UnaryOperator;
import java.util.stream.Collector;

import com.landawn.abacus.annotation.Beta;
import com.landawn.abacus.annotation.IntermediateOp;
import com.landawn.abacus.annotation.LazyEvaluation;
import com.landawn.abacus.annotation.ParallelSupported;
import com.landawn.abacus.annotation.SequentialOnly;
import com.landawn.abacus.annotation.TerminalOp;
import com.landawn.abacus.annotation.TerminalOpTriggered;
import com.landawn.abacus.exception.UncheckedIOException;
import com.landawn.abacus.util.Array;
import com.landawn.abacus.util.AsyncExecutor;
import com.landawn.abacus.util.ByteIterator;
import com.landawn.abacus.util.CharIterator;
import com.landawn.abacus.util.Charsets;
import com.landawn.abacus.util.ClassUtil;
import com.landawn.abacus.util.ContinuableFuture;
import com.landawn.abacus.util.DataSet;
import com.landawn.abacus.util.DoubleIterator;
import com.landawn.abacus.util.Duration;
import com.landawn.abacus.util.ExceptionalStream;
import com.landawn.abacus.util.ExceptionalStream.CheckedStream;
import com.landawn.abacus.util.FloatIterator;
import com.landawn.abacus.util.Fn;
import com.landawn.abacus.util.Fn.Fnn;
import com.landawn.abacus.util.Fn.Suppliers;
import com.landawn.abacus.util.Holder;
import com.landawn.abacus.util.IOUtil;
import com.landawn.abacus.util.ImmutableMap;
import com.landawn.abacus.util.Indexed;
import com.landawn.abacus.util.IntIterator;
import com.landawn.abacus.util.Iterators;
import com.landawn.abacus.util.Joiner;
import com.landawn.abacus.util.Keyed;
import com.landawn.abacus.util.LineIterator;
import com.landawn.abacus.util.ListMultimap;
import com.landawn.abacus.util.LongIterator;
import com.landawn.abacus.util.MergeResult;
import com.landawn.abacus.util.Multimap;
import com.landawn.abacus.util.MutableBoolean;
import com.landawn.abacus.util.MutableInt;
import com.landawn.abacus.util.MutableLong;
import com.landawn.abacus.util.N;
import com.landawn.abacus.util.NoCachingNoUpdating;
import com.landawn.abacus.util.NoCachingNoUpdating.DisposableEntry;
import com.landawn.abacus.util.ObjIterator;
import com.landawn.abacus.util.Pair;
import com.landawn.abacus.util.Percentage;
import com.landawn.abacus.util.RateLimiter;
import com.landawn.abacus.util.ShortIterator;
import com.landawn.abacus.util.Splitter;
import com.landawn.abacus.util.Throwables;
import com.landawn.abacus.util.u.Optional;
import com.landawn.abacus.util.u.OptionalDouble;
import com.landawn.abacus.util.u.OptionalInt;
import com.landawn.abacus.util.u.OptionalLong;
import com.landawn.abacus.util.function.ByteBiFunction;
import com.landawn.abacus.util.function.ByteNFunction;
import com.landawn.abacus.util.function.ByteTriFunction;
import com.landawn.abacus.util.function.CharBiFunction;
import com.landawn.abacus.util.function.CharNFunction;
import com.landawn.abacus.util.function.CharTriFunction;
import com.landawn.abacus.util.function.DoubleBiFunction;
import com.landawn.abacus.util.function.DoubleNFunction;
import com.landawn.abacus.util.function.DoubleTriFunction;
import com.landawn.abacus.util.function.FloatBiFunction;
import com.landawn.abacus.util.function.FloatNFunction;
import com.landawn.abacus.util.function.FloatTriFunction;
import com.landawn.abacus.util.function.IntBiFunction;
import com.landawn.abacus.util.function.IntNFunction;
import com.landawn.abacus.util.function.IntTriFunction;
import com.landawn.abacus.util.function.LongBiFunction;
import com.landawn.abacus.util.function.LongNFunction;
import com.landawn.abacus.util.function.LongTriFunction;
import com.landawn.abacus.util.function.ShortBiFunction;
import com.landawn.abacus.util.function.ShortNFunction;
import com.landawn.abacus.util.function.ShortTriFunction;
import com.landawn.abacus.util.function.ToByteFunction;
import com.landawn.abacus.util.function.ToCharFunction;
import com.landawn.abacus.util.function.ToFloatFunction;
import com.landawn.abacus.util.function.ToShortFunction;
import com.landawn.abacus.util.function.TriFunction;
import com.landawn.abacus.util.function.TriPredicate;
import com.landawn.abacus.util.stream.ObjIteratorEx.BufferedIterator;

/**
 * Note: This class includes codes copied from StreamEx: https://github.com/amaembo/streamex under Apache License, version 2.0.
 * 
* * The Stream will be automatically closed after execution(A terminal method is executed/triggered). * * @param the type of the stream elements * @see BaseStream * @see IntStream * @see LongStream * @see DoubleStream * @see EntryStream * @see com.landawn.abacus.util.ExceptionalStream * @see Collectors * @see com.landawn.abacus.util.Fn * @see com.landawn.abacus.util.Comparators */ @com.landawn.abacus.annotation.Immutable @LazyEvaluation @SuppressWarnings({ "java:S1192", "java:S1845" }) public abstract class Stream extends StreamBase, Consumer, List, Optional, Indexed, ObjIterator, Stream> { static final Random RAND = new SecureRandom(); Stream(final boolean sorted, final Comparator cmp, final Collection closeHandlers) { super(sorted, cmp, closeHandlers); } /** * Select the elements belong to the specified {@code targetType}(including its subtype). * * @param * @param targetType * @return */ @SequentialOnly @IntermediateOp public Stream select(final Class targetType) { if (isParallel()) { return (Stream) sequential().filter(Fn.instanceOf(targetType)) .parallel(maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(), cancelUncompletedThreads()); } else { return (Stream) filter(Fn.instanceOf(targetType)); } } /** * * @param predicate * @return */ @SequentialOnly @Beta @IntermediateOp @Override public Stream skipUntil(final Predicate predicate) { return dropWhile(Fn.not(predicate)); } /** * * * @param * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract Stream map(Function mapper); /** * * * @param * @param extractor * @return */ @ParallelSupported @IntermediateOp public Stream> pairWith(final Function extractor) { return map(t -> Pair.of(t, extractor.apply(t))); } // public abstract Stream biMap(BiFunction mapper); // // /** // * Returns a stream consisting of the results of applying the given function // * to the every two adjacent elements of this stream. // * // *
    //     * 
    //     * Stream.of("a", "b", "c", "d", "e").biMap((i, j) -> i + "-" + j).println();
    //     * // print out: [a-b, c-d, e-null]
    //     * 
    //     * 
// * // * @param mapper // * @param ignoreNotPaired flag to identify if need to ignore the last element when the total length of the stream is odd number. Default value is false // * @return // */ // public abstract Stream biMap(BiFunction mapper, boolean ignoreNotPaired); // // public abstract Stream triMap(TriFunction mapper); // // /** // * Returns a stream consisting of the results of applying the given function // * to the every three adjacent elements of this stream. // * // *
    //     * 
    //     * Stream.of("a", "b", "c", "d", "e").triMap((i, j, k) -> i + "-" + j + "-" + k).println();
    //     * // print out: [a-b-c, d-e-null]
    //     * 
    //     * 
// * // * @param mapper // * @param ignoreNotPaired flag to identify if need to ignore the last one or two elements when the total length of the stream is not multiple of 3. Default value is false // * @return // */ // public abstract Stream triMap(TriFunction mapper, boolean ignoreNotPaired); /** * * * @param * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract Stream slidingMap(BiFunction mapper); /** * Slide with windowSize = 2 and the specified increment, then map by the specified mapper. * * @param * @param mapper * @param increment * @return */ @ParallelSupported @IntermediateOp public abstract Stream slidingMap(BiFunction mapper, int increment); /** * * * @param * @param mapper * @param increment * @param ignoreNotPaired * @return */ @ParallelSupported @IntermediateOp public abstract Stream slidingMap(BiFunction mapper, int increment, boolean ignoreNotPaired); /** * * * @param * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract Stream slidingMap(TriFunction mapper); /** * Slide with windowSize = 3 and the specified increment, then map by the specified mapper. * * @param * @param mapper * @param increment * @return */ @ParallelSupported @IntermediateOp public abstract Stream slidingMap(TriFunction mapper, int increment); /** * * * @param * @param mapper * @param increment * @param ignoreNotPaired * @return */ @ParallelSupported @IntermediateOp public abstract Stream slidingMap(TriFunction mapper, int increment, boolean ignoreNotPaired); /** * Note: copied from StreamEx: https://github.com/amaembo/streamex * *
* * Returns a stream consisting of results of applying the given function to * the ranges created from the source elements. * *
     * 
     * Stream.of("a", "ab", "ac", "b", "c", "cb").rangeMap((a, b) -> b.startsWith(a), (a, b) -> a + "->" + b).toList(); // a->ac, b->b, c->cb
     * 
     * 
* *

* This is a quasi-intermediate * partial reduction operation. * * @param the type of the resulting elements * @param sameRange a non-interfering, stateless predicate to apply to * the leftmost and next elements which returns true for elements * which belong to the same range. * @param mapper a non-interfering, stateless function to apply to the * range borders and produce the resulting element. If value was * not merged to the interval, then mapper will receive the same * value twice, otherwise it will receive the leftmost and the * rightmost values which were merged to the range. * @return * @see #collapse(BiPredicate, BinaryOperator) */ @SequentialOnly @IntermediateOp public abstract Stream rangeMap(final BiPredicate sameRange, final BiFunction mapper); /** * * * @param mapperForFirst * @return */ @SequentialOnly @IntermediateOp public abstract Stream mapFirst(Function mapperForFirst); /** * * * @param * @param mapperForFirst * @param mapperForElse * @return */ @ParallelSupported @IntermediateOp public abstract Stream mapFirstOrElse(Function mapperForFirst, Function mapperForElse); /** * * * @param mapperForLast * @return */ @SequentialOnly @IntermediateOp public abstract Stream mapLast(Function mapperForLast); /** * * * @param * @param mapperForLast * @param mapperForElse * @return */ @ParallelSupported @IntermediateOp public abstract Stream mapLastOrElse(Function mapperForLast, Function mapperForElse); /** * * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract CharStream mapToChar(ToCharFunction mapper); /** * * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract ByteStream mapToByte(ToByteFunction mapper); /** * * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract ShortStream mapToShort(ToShortFunction mapper); /** * * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract IntStream mapToInt(ToIntFunction mapper); /** * * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract LongStream mapToLong(ToLongFunction mapper); /** * * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract FloatStream mapToFloat(ToFloatFunction mapper); /** * * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract DoubleStream mapToDouble(ToDoubleFunction mapper); // public abstract EntryStream mapToEntry(); /** * * * @param * @param * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract EntryStream mapToEntry(Function> mapper); /** * * * @param * @param * @param keyMapper * @param valueMapper * @return */ @ParallelSupported @IntermediateOp public abstract EntryStream mapToEntry(Function keyMapper, Function valueMapper); // public abstract Stream mapp(Function> mapper); /** * * * @param * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract Stream flatMap(Function> mapper); /** * * * @param * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract Stream flatmap(Function> mapper); /** * * * @param * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract Stream flattMap(Function mapper); /** * * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract CharStream flatMapToChar(Function mapper); /** * * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract CharStream flatmapToChar(Function mapper); /** * * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract ByteStream flatMapToByte(Function mapper); /** * * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract ByteStream flatmapToByte(Function mapper); /** * * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract ShortStream flatMapToShort(Function mapper); /** * * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract ShortStream flatmapToShort(Function mapper); /** * * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract IntStream flatMapToInt(Function mapper); /** * * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract IntStream flatmapToInt(Function mapper); /** * * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract LongStream flatMapToLong(Function mapper); /** * * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract LongStream flatmapToLong(Function mapper); /** * * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract FloatStream flatMapToFloat(Function mapper); /** * * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract FloatStream flatmapToFloat(Function mapper); /** * * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract DoubleStream flatMapToDouble(Function mapper); /** * * * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract DoubleStream flatmapToDouble(Function mapper); /** * * * @param * @param * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract EntryStream flatMapToEntry(Function>> mapper); /** * * * @param * @param * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract EntryStream flatmapToEntry(Function> mapper); /** * * * @param * @param * @param mapper * @return */ @ParallelSupported @IntermediateOp public abstract EntryStream flattMapToEntry(Function> mapper); //NOSONAR /** * * * @param * @param mapper * @return * @implNote same as ====> *

     * skipNulls().flatmap(mapper)
     * 
*/ @Beta @ParallelSupported @IntermediateOp public Stream flatMapIfNotNull(Function> mapper) { return skipNulls().flatmap(mapper); } /** * * * @param * @param * @param mapper * @param mapper2 * @return * @implNote same as ====> *
     * skipNulls().flatmap(mapper).skipNulls().flatmap(mapper2)
     * 
*/ @Beta @ParallelSupported @IntermediateOp public Stream flatMapIfNotNull(Function> mapper, Function> mapper2) { return skipNulls().flatmap(mapper).skipNulls().flatmap(mapper2); } /** * * * @param * @param mapper * @return */ @Beta @ParallelSupported @IntermediateOp public abstract Stream mapMulti(BiConsumer> mapper); /** * * * @param mapper * @return */ @Beta @ParallelSupported @IntermediateOp public abstract IntStream mapMultiToInt(BiConsumer mapper); /** * * * @param mapper * @return */ @Beta @ParallelSupported @IntermediateOp public abstract LongStream mapMultiToLong(BiConsumer mapper); /** * * * @param mapper * @return */ @Beta @ParallelSupported @IntermediateOp public abstract DoubleStream mapMultiToDouble(BiConsumer mapper); /** * Note: copied from StreamEx: https://github.com/amaembo/streamex * * @param * @param mapper * @return */ @Beta @ParallelSupported @IntermediateOp public abstract Stream mapPartial(Function> mapper); /** * Note: copied from StreamEx: https://github.com/amaembo/streamex * * @param mapper * @return */ @Beta @ParallelSupported @IntermediateOp public abstract IntStream mapPartialToInt(Function mapper); /** * Note: copied from StreamEx: https://github.com/amaembo/streamex * * @param mapper * @return */ @Beta @ParallelSupported @IntermediateOp public abstract LongStream mapPartialToLong(Function mapper); /** * Note: copied from StreamEx: https://github.com/amaembo/streamex * * @param mapper * @return */ @Beta @ParallelSupported @IntermediateOp public abstract DoubleStream mapPartialToDouble(Function mapper); /** * Note: copied from StreamEx: https://github.com/amaembo/streamex * * @param * @param mapper * @return */ @Beta @ParallelSupported @IntermediateOp public abstract Stream mapPartialJdk(Function> mapper); /** * Note: copied from StreamEx: https://github.com/amaembo/streamex * * @param mapper * @return */ @Beta @ParallelSupported @IntermediateOp public abstract IntStream mapPartialToIntJdk(Function mapper); /** * Note: copied from StreamEx: https://github.com/amaembo/streamex * * @param mapper * @return */ @Beta @ParallelSupported @IntermediateOp public abstract LongStream mapPartialToLongJdk(Function mapper); /** * Note: copied from StreamEx: https://github.com/amaembo/streamex * * @param mapper * @return */ @Beta @ParallelSupported @IntermediateOp public abstract DoubleStream mapPartialToDoubleJdk(Function mapper); /** * * * @param * @param keyMapper * @return */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract Stream>> groupBy(final Function keyMapper); /** * * * @param * @param keyMapper * @param mapFactory * @return */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract Stream>> groupBy(final Function keyMapper, final Supplier>> mapFactory); /** * * * @param * @param * @param keyMapper * @param valueMapper * @return * @see Collectors#toMultimap(Function, Function) */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract Stream>> groupBy(Function keyMapper, Function valueMapper); /** * * * @param * @param * @param keyMapper * @param valueMapper * @param mapFactory * @return * @see Collectors#toMultimap(Function, Function, Supplier) */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract Stream>> groupBy(Function keyMapper, Function valueMapper, Supplier>> mapFactory); /** * * * @param * @param * @param * @param keyMapper * @param downstream * @return */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract Stream> groupBy(final Function keyMapper, final Collector downstream); /** * * * @param * @param * @param * @param keyMapper * @param downstream * @param mapFactory * @return */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract Stream> groupBy(final Function keyMapper, final Collector downstream, final Supplier> mapFactory); /** * * * @param * @param * @param * @param * @param keyMapper * @param valueMapper * @param downstream * @return */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract Stream> groupBy(final Function keyMapper, final Function valueMapper, final Collector downstream); /** * * @param * @param * @param // TODO do we need A * @param * @param keyMapper * @param valueMapper * @param downstream * @param mapFactory * @return */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract Stream> groupBy(final Function keyMapper, final Function valueMapper, final Collector downstream, final Supplier> mapFactory); /** * * * @param * @param * @param keyMapper * @param valueMapper * @param mergeFunction * @return */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract Stream> groupBy(final Function keyMapper, final Function valueMapper, BinaryOperator mergeFunction); /** * * * @param * @param * @param keyMapper * @param valueMapper * @param mergeFunction * @param mapFactory * @return */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract Stream> groupBy(final Function keyMapper, final Function valueMapper, final BinaryOperator mergeFunction, final Supplier> mapFactory); // @ParallelSupported // public abstract Stream>> flatGroupBy(final Throwables.Function, E> flatKeyMapper); // // @ParallelSupported // public abstract Stream>> flatGroupBy(final Throwables.Function, E> flatKeyMapper, // final Supplier>> mapFactory); // // /** // * // * @param flatKeyMapper // * @param valueMapper // * @return // * @see Collectors#toMultimap(Function, Function) // */ // @ParallelSupported // public abstract Stream>> flatGroupBy(Throwables.Function, E> flatKeyMapper, // Throwables.BiFunction valueMapper); // // /** // * // * @param flatKeyMapper // * @param valueMapper // * @param mapFactory // * @return // * @see Collectors#toMultimap(Function, Function, Supplier) // */ // @ParallelSupported // public abstract Stream>> flatGroupBy(Throwables.Function, E> flatKeyMapper, // Throwables.BiFunction valueMapper, Supplier>> mapFactory); // // @ParallelSupported // public abstract Stream> flatGroupBy(final Throwables.Function, E> flatKeyMapper, // final Collector downstream); // // @ParallelSupported // public abstract Stream> flatGroupBy(final Throwables.Function, E> flatKeyMapper, // final Collector downstream, final Supplier> mapFactory); // // @ParallelSupported // public abstract Stream> flatGroupBy(final Throwables.Function, E> flatKeyMapper, // final Throwables.BiFunction valueMapper, final Collector downstream); // // @ParallelSupported // public abstract Stream> flatGroupBy(final Throwables.Function, E> flatKeyMapper, // final Throwables.BiFunction valueMapper, final Collector downstream, // final Supplier> mapFactory); // // @ParallelSupported // public abstract Stream> flatGroupBy(final Throwables.Function, E> flatKeyMapper, // final Throwables.BiFunction valueMapper, BinaryOperator mergeFunction); // // @ParallelSupported // public abstract Stream> flatGroupBy(final Throwables.Function, E> flatKeyMapper, // final Throwables.BiFunction valueMapper, final BinaryOperator mergeFunction, // final Supplier> mapFactory); // // @ParallelSupported // public abstract Stream>> flattGroupBy(final Throwables.Function, E> flatKeyMapper); // // @ParallelSupported // public abstract Stream>> flattGroupBy(final Throwables.Function, E> flatKeyMapper, // final Supplier>> mapFactory); // // /** // * // * @param flatKeyMapper // * @param valueMapper // * @return // * @see Collectors#toMultimap(Function, Function) // */ // @ParallelSupported // public abstract Stream>> flattGroupBy(Throwables.Function, E> flatKeyMapper, // Throwables.BiFunction valueMapper); // // /** // * // * @param flatKeyMapper // * @param valueMapper // * @param mapFactory // * @return // * @see Collectors#toMultimap(Function, Function, Supplier) // */ // @ParallelSupported // public abstract Stream>> flattGroupBy(Throwables.Function, E> flatKeyMapper, // Throwables.BiFunction valueMapper, Supplier>> mapFactory); // // @ParallelSupported // public abstract Stream> flattGroupBy(final Throwables.Function, E> flatKeyMapper, // final Collector downstream); // // @ParallelSupported // public abstract Stream> flattGroupBy(final Throwables.Function, E> flatKeyMapper, // final Collector downstream, final Supplier> mapFactory); // // @ParallelSupported // public abstract Stream> flattGroupBy(final Throwables.Function, E> flatKeyMapper, // final Throwables.BiFunction valueMapper, final Collector downstream); // // @ParallelSupported // public abstract Stream> flattGroupBy(final Throwables.Function, E> flatKeyMapper, // final Throwables.BiFunction valueMapper, final Collector downstream, // final Supplier> mapFactory); // // @ParallelSupported // public abstract Stream> flattGroupBy(final Throwables.Function, E> flatKeyMapper, // final Throwables.BiFunction valueMapper, BinaryOperator mergeFunction); // // @ParallelSupported // public abstract Stream> flattGroupBy(final Throwables.Function, E> flatKeyMapper, // final Throwables.BiFunction valueMapper, final BinaryOperator mergeFunction, // final Supplier> mapFactory); /** * * * @param * @param keyMapper * @return */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract EntryStream> groupByToEntry(final Function keyMapper); /** * * * @param * @param keyMapper * @param mapFactory * @return */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract EntryStream> groupByToEntry(final Function keyMapper, final Supplier>> mapFactory); /** * * * @param * @param * @param keyMapper * @param valueMapper * @return * @see Collectors#toMultimap(Function, Function) */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract EntryStream> groupByToEntry(Function keyMapper, Function valueMapper); /** * * * @param * @param * @param keyMapper * @param valueMapper * @param mapFactory * @return * @see Collectors#toMultimap(Function, Function, Supplier) */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract EntryStream> groupByToEntry(Function keyMapper, Function valueMapper, Supplier>> mapFactory); /** * * * @param * @param * @param * @param keyMapper * @param downstream * @return */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract EntryStream groupByToEntry(final Function keyMapper, final Collector downstream); /** * * * @param * @param * @param * @param keyMapper * @param downstream * @param mapFactory * @return */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract EntryStream groupByToEntry(final Function keyMapper, final Collector downstream, final Supplier> mapFactory); /** * * * @param * @param * @param * @param * @param keyMapper * @param valueMapper * @param downstream * @return */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract EntryStream groupByToEntry(final Function keyMapper, final Function valueMapper, final Collector downstream); /** * * * @param * @param * @param * @param * @param keyMapper * @param valueMapper * @param downstream * @param mapFactory * @return */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract EntryStream groupByToEntry(final Function keyMapper, final Function valueMapper, final Collector downstream, final Supplier> mapFactory); /** * * * @param * @param * @param keyMapper * @param valueMapper * @param mergeFunction * @return */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract EntryStream groupByToEntry(final Function keyMapper, final Function valueMapper, BinaryOperator mergeFunction); /** * * * @param * @param * @param keyMapper * @param valueMapper * @param mergeFunction * @param mapFactory * @return */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract EntryStream groupByToEntry(final Function keyMapper, final Function valueMapper, final BinaryOperator mergeFunction, final Supplier> mapFactory); /** * * @param predicate * @return * @see Collectors#partitioningBy(Predicate) */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract Stream>> partitionBy(final Predicate predicate); /** * * * @param * @param * @param predicate * @param downstream * @return * @see Collectors#partitioningBy(Predicate, Collector) */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract Stream> partitionBy(final Predicate predicate, final Collector downstream); /** * * @param predicate * @return * @see Collectors#partitioningBy(Predicate) */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract EntryStream> partitionByToEntry(final Predicate predicate); /** * * * @param * @param * @param predicate * @param downstream * @return * @see Collectors#partitioningBy(Predicate, Collector) */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract EntryStream partitionByToEntry(final Predicate predicate, final Collector downstream); /** * * * @param * @param keyMapper * @return */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public Stream> countBy(final Function keyMapper) { return groupBy(keyMapper, Collectors.countingInt()); } /** * * * @param * @param keyMapper * @return */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public EntryStream countByToEntry(final Function keyMapper) { return groupByToEntry(keyMapper, Collectors.countingInt()); } /** * * @param collapsible test the current element with its previous element. The first parameter is the previous element of current element, the second parameter is the current element. * @return */ @SequentialOnly @IntermediateOp public abstract Stream> collapse(final BiPredicate collapsible); /** * * @param * @param collapsible test the current element with its previous element. The first parameter is the previous element of current element, the second parameter is the current element. * @param supplier * @return */ @SequentialOnly @IntermediateOp public abstract > Stream collapse(final BiPredicate collapsible, Supplier supplier); /** * 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((p, c) -> p < c, (r, c) -> r + c) => []
     * Stream.of(1).collapse((p, c) -> p < c, (r, c) -> r + c) => [1]
     * Stream.of(1, 2).collapse((p, c) -> p < c, (r, c) -> r + c) => [3]
     * Stream.of(1, 2, 3).collapse((p, c) -> p < c, (r, c) -> r + c) => [6]
     * Stream.of(1, 2, 3, 3, 2, 1).collapse((p, c) -> p < c, (r, c) -> r + c) => [6, 3, 2, 1]
     * 
     * 
* *
* This method only runs sequentially, even in parallel stream. * * @param collapsible test the current element with its previous element. The first parameter is the previous element of current element, the second parameter is the current element. * @param mergeFunction * @return */ @SequentialOnly @IntermediateOp public abstract Stream collapse(final BiPredicate collapsible, final BiFunction mergeFunction); /** * * @param * @param collapsible test the current element with its previous element. The first parameter is the previous element of current element, the second parameter is the current element. * @param init is used by {@code op} to generate the first result value in the series. * @param op * @return */ @SequentialOnly @IntermediateOp public abstract Stream collapse(final BiPredicate collapsible, final U init, final BiFunction op); /** * * @param * @param collapsible test the current element with its previous element. The first parameter is the previous element of current element, the second parameter is the current element. * @param supplier * @param accumulator * @return */ @SequentialOnly @IntermediateOp public abstract Stream collapse(final BiPredicate collapsible, final Supplier supplier, final BiConsumer accumulator); /** * 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((p, c) -> p < c, Collectors.summingInt(Fn.unboxI())) => []
     * Stream.of(1).collapse((p, c) -> p < c, Collectors.summingInt(Fn.unboxI())) => [1]
     * Stream.of(1, 2).collapse((p, c) -> p < c, Collectors.summingInt(Fn.unboxI())) => [3]
     * Stream.of(1, 2, 3).collapse((p, c) -> p < c, Collectors.summingInt(Fn.unboxI())) => [6]
     * Stream.of(1, 2, 3, 3, 2, 1).collapse((p, c) -> p < c, Collectors.summingInt(Fn.unboxI())) => [6, 3, 2, 1]
     * 
     * 
* *
* This method only runs sequentially, even in parallel stream. * * @param * @param
* @param collapsible test the current element with its previous element. The first parameter is the previous element of current element, the second parameter is the current element. * @param collector * @return */ @SequentialOnly @IntermediateOp public abstract Stream collapse(final BiPredicate collapsible, final Collector collector); /** * * @param collapsible test the current element with the first element and previous element in the series. The first parameter is the first element of this series, the second parameter is the previous element and the third parameter is the current element. * @return */ @Beta @SequentialOnly @IntermediateOp public abstract Stream> collapse(final TriPredicate collapsible); /** * * @param * @param collapsible test the current element with the first element and previous element in the series. The first parameter is the first element of this series, the second parameter is the previous element and the third parameter is the current element. * @param supplier * @return */ @Beta @SequentialOnly @IntermediateOp public abstract > Stream collapse(final TriPredicate collapsible, Supplier supplier); /** * 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((f, p, c) -> f < c, (r, c) -> r + c) => []
     * Stream.of(1).collapse((f, p, c) -> f < c, (r, c) -> r + c) => [1]
     * Stream.of(1, 2).collapse((f, p, c) -> f < c, (r, c) -> r + c) => [3]
     * Stream.of(1, 2, 3).collapse((f, p, c) -> f < c, (r, c) -> r + c) => [6]
     * Stream.of(1, 2, 3, 3, 2, 1).collapse((f, p, c) -> f < c, (r, c) -> r + c) => [11, 1]
     * 
     * 
* *
* This method only runs sequentially, even in parallel stream. * * @param collapsible test the current element with the first element and previous element in the series. The first parameter is the first element of this series, the second parameter is the previous element and the third parameter is the current element. * @param mergeFunction * @return */ @Beta @SequentialOnly @IntermediateOp public abstract Stream collapse(final TriPredicate collapsible, final BiFunction mergeFunction); /** * * @param * @param collapsible test the current element with the first element and previous element in the series. The first parameter is the first element of this series, the second parameter is the previous element and the third parameter is the current element. * @param init is used by {@code op} to generate the first result value in the series. * @param op * @return */ @Beta @SequentialOnly @IntermediateOp public abstract Stream collapse(final TriPredicate collapsible, final U init, final BiFunction op); /** * * @param * @param collapsible test the current element with the first element and previous element in the series. The first parameter is the first element of this series, the second parameter is the previous element and the third parameter is the current element. * @param supplier * @param accumulator * @return */ @Beta @SequentialOnly @IntermediateOp public abstract Stream collapse(final TriPredicate collapsible, final Supplier supplier, final BiConsumer accumulator); /** * 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((f, p, c) -> f < c, Collectors.summingInt(Fn.unboxI())) => []
     * Stream.of(1).collapse((f, p, c) -> f < c, Collectors.summingInt(Fn.unboxI())) => [1]
     * Stream.of(1, 2).collapse((f, p, c) -> f < c, Collectors.summingInt(Fn.unboxI())) => [3]
     * Stream.of(1, 2, 3).collapse((f, p, c) -> f < c, Collectors.summingInt(Fn.unboxI())) => [6]
     * Stream.of(1, 2, 3, 3, 2, 1).collapse((f, p, c) -> f < c, Collectors.summingInt(Fn.unboxI())) => [11, 1]
     * 
     * 
* *
* This method only runs sequentially, even in parallel stream. * * @param * @param
* @param collapsible test the current element with the first element and previous element in the series. The first parameter is the first element of this series, the second parameter is the previous element and the third parameter is the current element. * @param collector * @return */ @Beta @SequentialOnly @IntermediateOp public abstract Stream collapse(final TriPredicate collapsible, final Collector collector); /** * Returns a {@code Stream} produced by iterative application of a accumulation function * to an initial element {@code init} and next element of the current stream. * Produces a {@code Stream} consisting of {@code init}, {@code acc(init, value1)}, * {@code acc(acc(init, value1), value2)}, etc. * *

This is an intermediate operation. * *

Example: *

     * 
     * Stream.of(new Integer[0]).scan((r, c) -> r + c) => []
     * Stream.of(1).scan((r, c) -> r + c) => [1]
     * Stream.of(1, 2).scan((r, c) -> r + c) => [1, 3]
     * Stream.of(1, 2, 3).scan((r, c) -> r + c) => [1, 3, 6]
     * Stream.of(1, 2, 3, 3, 2, 1).scan((r, c) -> r + c) => [1, 3, 6, 9, 11, 12]
     * 
     * 
* *
* This method only runs sequentially, even in parallel stream. * * @param accumulator the accumulation function * @return */ @SequentialOnly @IntermediateOp public abstract Stream scan(final BiFunction accumulator); /** * Returns a {@code Stream} produced by iterative application of a accumulation function * to an initial element {@code init} and next element of the current stream. * Produces a {@code Stream} consisting of {@code init}, {@code acc(init, value1)}, * {@code acc(acc(init, value1), value2)}, etc. * *

This is an intermediate operation. * *

Example: *

     * 
     * Stream.of(new Integer[0]).scan(10, (r, c) -> r + c) => []
     * Stream.of(1).scan(10, (r, c) -> r + c) => [11]
     * Stream.of(1, 2).scan(10, (r, c) -> r + c) => [11, 13]
     * Stream.of(1, 2, 3).scan(10, (r, c) -> r + c) => [11, 13, 16]
     * Stream.of(1, 2, 3, 3, 2, 1).scan(10, (r, c) -> r + c) => [11, 13, 16, 19, 21, 22]
     * 
     * 
* *
* This method only runs sequentially, even in parallel stream. * * @param * @param init the initial value. it's only used once by accumulator to calculate the fist element in the returned stream. * It will be ignored if this stream is empty and won't be the first element of the returned stream. * @param accumulator the accumulation function * @return */ @SequentialOnly @IntermediateOp public abstract Stream scan(final U init, final BiFunction accumulator); /** * * * @param * @param init * @param accumulator * @param initIncluded * @return */ @SequentialOnly @IntermediateOp public abstract Stream scan(final U init, final BiFunction accumulator, final boolean initIncluded); // @SequentialOnly // @IntermediateOp // public Stream scanInclusive(final U init, final BiFunction accumulator) { // return scan(init, accumulator, true); // } /** * Returns Stream of Stream with consecutive sub sequences of the elements, each of the same size (the final sequence may be smaller). * *
* This method only runs sequentially, even in parallel stream. * * @param chunkSize the desired size of each sub sequence (the last may be smaller). * @return */ @SequentialOnly @IntermediateOp public abstract Stream> splitToSet(int chunkSize); /** * Returns Stream of Stream with consecutive sub sequences of the elements, each of the same size (the final sequence may be smaller). * *
* This method only runs sequentially, even in parallel stream. * * @param * @param chunkSize the desired size of each sub sequence (the last may be smaller). * @param collectionSupplier * @return */ @SequentialOnly @IntermediateOp public abstract > Stream split(int chunkSize, IntFunction collectionSupplier); /** * * * @param
* @param * @param chunkSize the desired size of each sub sequence (the last may be smaller). * @param collector * @return */ @SequentialOnly @IntermediateOp public abstract Stream split(int chunkSize, Collector collector); /** * * * @param predicate * @return */ @SequentialOnly @IntermediateOp public abstract Stream> splitToSet(Predicate predicate); /** * * * @param * @param predicate * @param collectionSupplier * @return */ @SequentialOnly @IntermediateOp public abstract > Stream split(Predicate predicate, Supplier collectionSupplier); /** * * * @param * @param * @param predicate * @param collector * @return */ @SequentialOnly @IntermediateOp public abstract Stream split(Predicate predicate, Collector collector); /** * Split the stream into two pieces at where turns to {@code false}. * The first piece will be loaded into memory. * * @param * @param * @param where * @param collector * @return */ @SequentialOnly @IntermediateOp public abstract Stream splitAt(int where, Collector collector); /** * Split the stream into two pieces at where turns to {@code false}. * The first piece will be loaded into memory. * * @param * @param * @param where * @param collector * @return */ @SequentialOnly @IntermediateOp public abstract Stream splitAt(Predicate where, Collector collector); /** * * @param windowSize * @return * @see #sliding(int, int) */ @SequentialOnly @IntermediateOp public Stream> slidingToSet(int windowSize) { return slidingToSet(windowSize, 1); } /** * * @param windowSize * @param increment * @return * @see #sliding(int, int) */ @SequentialOnly @IntermediateOp public abstract Stream> slidingToSet(int windowSize, int increment); /** * * * @param * @param windowSize * @param collectionSupplier * @return */ @SequentialOnly @IntermediateOp public abstract > Stream sliding(int windowSize, IntFunction collectionSupplier); /** * * * @param * @param windowSize * @param increment * @param collectionSupplier * @return */ @SequentialOnly @IntermediateOp public abstract > Stream sliding(int windowSize, int increment, IntFunction collectionSupplier); /** * * * @param * @param * @param windowSize * @param collector * @return */ @SequentialOnly @IntermediateOp public abstract Stream sliding(int windowSize, Collector collector); /** * * * @param * @param * @param windowSize * @param increment * @param collector * @return */ @SequentialOnly @IntermediateOp public abstract Stream sliding(int windowSize, int increment, Collector collector); /** * Stream.of(1).intersperse(9) --> [1] * Stream.of(1, 2, 3).intersperse(9) --> [1, 9, 2, 9, 3] * *
* This method only runs sequentially, even in parallel stream. * * @param delimiter * @return */ @SequentialOnly @IntermediateOp public abstract Stream intersperse(T delimiter); /** * Distinct and merge duplicated elements. * * @param mergeFunction * @return * @see #groupBy(Function, Function, BinaryOperator) */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public Stream distinct(final BinaryOperator mergeFunction) { // ConcurrentHashMap is not required for parallel stream and it doesn't support null key. // final Supplier> supplier = isParallel() ? Suppliers. ofConcurrentHashMap() : Suppliers. ofLinkedHashMap(); final Supplier> supplier = Suppliers. ofMap(); if (isParallel()) { return groupBy(Fn. identity(), Fn. identity(), mergeFunction, supplier) // .sequential() .map(Fn.value()) .parallel(maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(), cancelUncompletedThreads()); } else { return groupBy(Fn. identity(), Fn. identity(), mergeFunction, supplier).map(Fn.value()); } } /** * Distinct and filter by occurrences. * * @param occurrencesFilter * @return */ @SequentialOnly @IntermediateOp @TerminalOpTriggered public Stream distinct(final Predicate occurrencesFilter) { // ConcurrentHashMap is not required for parallel stream and it doesn't support null key. // final Supplier> supplier = isParallel() ? Suppliers. ofConcurrentHashMap() : Suppliers. ofLinkedHashMap(); final Supplier> supplier = Suppliers. ofLinkedHashMap(); if (isParallel()) { return newStream(sequential() // .groupBy(Fn. identity(), Collectors.counting(), supplier) .filter(Fn. testByValue(occurrencesFilter)) // .map(Fn. key()) .iteratorEx(), sorted, cmp); } else { return newStream(groupBy(Fn. identity(), Collectors.counting(), supplier) // .filter(Fn. testByValue(occurrencesFilter)) .map(Fn. key()) .iteratorEx(), sorted, cmp); } } /** * Distinct by the value mapped from keyMapper. * * @param keyMapper don't change value of the input parameter. * @return */ @ParallelSupported @IntermediateOp public abstract Stream distinctBy(Function keyMapper); /** * Distinct and merge duplicated elements. * * @param * @param keyMapper * @param mergeFunction * @return * @see #groupBy(Function, Function, BinaryOperator) */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public Stream distinctBy(final Function keyMapper, final BinaryOperator mergeFunction) { // ConcurrentHashMap is not required for parallel stream and it doesn't support null key. // final Supplier> supplier = isParallel() ? Suppliers. ofConcurrentHashMap() : Suppliers. ofLinkedHashMap(); final Supplier> supplier = Suppliers. ofMap(); if (isParallel()) { return groupBy(keyMapper, Fn. identity(), mergeFunction, supplier) // .sequential() .map(Fn.value()) .parallel(maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(), cancelUncompletedThreads()); } else { return groupBy(keyMapper, Fn. identity(), mergeFunction, supplier).sequential().map(Fn.value()); } } /** * Distinct and filter by occurrences. * * @param * @param keyMapper * @param occurrencesFilter * @return * @see #groupBy(Function, Collector) */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public Stream distinctBy(final Function keyMapper, final Predicate occurrencesFilter) { // ConcurrentHashMap is not required for parallel stream and it doesn't support null key. // final Supplier, Long>> supplier = isParallel() ? Suppliers., Long> ofConcurrentHashMap() // : Suppliers., Long> ofLinkedHashMap(); final Supplier, Long>> supplier = Suppliers., Long> ofMap(); if (isParallel()) { return groupBy(Fn. keyed(keyMapper), Collectors.counting(), supplier) // .sequential() .filter(Fn., Long> testByValue(occurrencesFilter)) .map(Fn. kkv()) .parallel(maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(), cancelUncompletedThreads()); } else { return groupBy(Fn. keyed(keyMapper), Collectors.counting(), supplier) // .filter(Fn., Long> testByValue(occurrencesFilter)) .map(Fn. kkv()); } } /** * * * @param comparator * @return */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract Stream sorted(Comparator comparator); /** * * * @param keyMapper * @return */ @SuppressWarnings("rawtypes") @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract Stream sortedBy(Function keyMapper); /** * * * @param keyMapper * @return */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract Stream sortedByInt(ToIntFunction keyMapper); /** * * * @param keyMapper * @return */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract Stream sortedByLong(ToLongFunction keyMapper); /** * * * @param keyMapper * @return */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract Stream sortedByDouble(ToDoubleFunction keyMapper); /** * * * @param comparator * @return */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract Stream reverseSorted(Comparator comparator); /** * *
* This method only runs sequentially, even in parallel stream. * * @param n * @return */ @SequentialOnly @IntermediateOp public abstract Stream top(int n); /** *
* This method only runs sequentially, even in parallel stream. * * @param n * @param comparator * @return */ @SequentialOnly @IntermediateOp public abstract Stream top(int n, Comparator comparator); /** * Skip the range: [fromIndexInclusive, fromIndexInclusive]. * * @param startInclusive * @param endExclusive * @return */ @SequentialOnly @IntermediateOp public abstract Stream skipRange(int startInclusive, int endExclusive); /** * * * @return * @deprecated Use {@link #skipNulls()} instead */ @Deprecated @SequentialOnly @IntermediateOp public abstract Stream skipNull(); /** * * * @return */ @SequentialOnly @IntermediateOp public abstract Stream skipNulls(); /** * A queue with size up to n will be maintained to filter out the last n elements. * It may cause out of memory error if n is big enough. * *
* This method only runs sequentially, even in parallel stream. * * @param n * @return */ @SequentialOnly @IntermediateOp public abstract Stream skipLast(int n); /** * A queue with size up to n will be maintained to filter out the last n elements. * It may cause out of memory error if n is big enough. * *
* * All the elements will be loaded to get the last {@code n} elements and the Stream will be closed after that, if a terminal operation is triggered. * * @param n * @return */ @Beta @SequentialOnly @IntermediateOp public abstract Stream last(int n); /** * * * @param rateLimiter * @return */ @Override public Stream rateLimited(final RateLimiter rateLimiter) { checkArgNotNull(rateLimiter, "rateLimiter"); final Consumer action = it -> rateLimiter.acquire(); if (isParallel()) { return sequential().onEach(action).parallel(maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(), cancelUncompletedThreads()); } else { return onEach(action); } } // // This is not frequently used method. it should not be defined as an api. // @Beta // @SequentialOnly // @IntermediateOp // public Stream> timed() { // if (isParallel()) { // return sequential().map(Timed::of).parallel(maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(), cancelUncompletedThreads()); // } else { // return map(Timed::of); // } // } /** * * * @param action * @return */ @SequentialOnly @IntermediateOp public abstract Stream peekFirst(Consumer action); /** * * * @param action * @return */ @SequentialOnly @IntermediateOp public abstract Stream peekLast(Consumer action); /** * * @param predicate * @param action * @return */ @Beta @IntermediateOp public Stream peekIf(final Predicate predicate, final Consumer action) { checkArgNotNull(predicate, "predicate"); checkArgNotNull(action, "action"); return peek(Fn.acceptIf(predicate, action)); } /** * * @param predicate The first parameter is the element. The second parameter is the count of iterated elements, starts with 1. * @param action * @return */ @Beta @IntermediateOp public Stream peekIf(final BiPredicate predicate, final Consumer action) { checkArgNotNull(predicate, "predicate"); checkArgNotNull(action, "action"); if (this.isParallel()) { final AtomicLong count = new AtomicLong(); return onEach(it -> { if (predicate.test(it, count.incrementAndGet())) { action.accept(it); } }); } else { final MutableLong count = MutableLong.of(0); return onEach(it -> { if (predicate.test(it, count.incrementAndGet())) { action.accept(it); } }); } } // TODO First of all, it only works in sequential Stream, not parallel stream (and maybe not work in some other scenarios as well). // Secondly, these onErrorXXX methods make it more difficult and complicated to use Stream. // So, remove them. // /** // * This method should be only applied sequential {@code Stream} and whose up-streams are sequential {@code Streams} as well. // * Because error happening in the operations executed by parallel stream will stop iteration on that {@Stream}, so the down-streams won't be able to continue. // * // * @param errorConsumer // * @return // */ // @Beta // @SequentialOnly // @IntermediateOp // public abstract Stream onErrorContinue(Consumer errorConsumer); // // /** // * This method should be only applied sequential {@code Stream} and whose up-streams are sequential {@code Streams} as well. // * Because error happening in the operations executed by parallel stream will stop iteration on that {@Stream}, so the down-streams won't be able to continue. // * // * @param type // * @param errorConsumer // * @return // */ // @Beta // @SequentialOnly // @IntermediateOp // public abstract Stream onErrorContinue(Class type, Consumer errorConsumer); // // /** // * This method should be only applied sequential {@code Stream} and whose up-streams are sequential {@code Streams} as well. // * Because error happening in the operations executed by parallel stream will stop iteration on that {@Stream}, so the down-streams won't be able to continue. // * // * @param errorPredicate // * @param errorConsumer // * @return // */ // @Beta // @SequentialOnly // @IntermediateOp // public abstract Stream onErrorContinue(Predicate errorPredicate, Consumer errorConsumer); // // /** // * This method should be only applied sequential {@code Stream} and whose up-streams are sequential {@code Streams} as well. // * Because error happening in the operations executed by parallel stream will stop iteration on that {@Stream}, so the down-streams won't be able to continue. // * // * @param errorPredicate // * @param errorConsumer // * @param maxErrorCountToStop // * @return // */ // @Beta // @SequentialOnly // @IntermediateOp // public abstract Stream onErrorContinue(Predicate errorPredicate, Consumer errorConsumer, int maxErrorCountToStop); // // /** // * This method should be only applied sequential {@code Stream} and whose up-streams are sequential {@code Streams} as well. // * Because error happening in the operations executed by parallel stream will stop iteration on that {@Stream}, so the down-streams won't be able to continue. // * // * @param fallbackValue // * @return // */ // @Beta // @SequentialOnly // @IntermediateOp // public abstract Stream onErrorReturn(T fallbackValue); // // /** // * This method should be only applied sequential {@code Stream} and whose up-streams are sequential {@code Streams} as well. // * Because error happening in the operations executed by parallel stream will stop iteration on that {@Stream}, so the down-streams won't be able to continue. // * // * @param type // * @param fallbackValue // * @return // */ // @Beta // @SequentialOnly // @IntermediateOp // public abstract Stream onErrorReturn(Class type, T fallbackValue); // // /** // * This method should be only applied sequential {@code Stream} and whose up-streams are sequential {@code Streams} as well. // * Because error happening in the operations executed by parallel stream will stop iteration on that {@Stream}, so the down-streams won't be able to continue. // * // * @param predicate // * @param fallbackValue // * @return // */ // @Beta // @SequentialOnly // @IntermediateOp // public abstract Stream onErrorReturn(Predicate predicate, T fallbackValue); // // /** // * This method should be only applied sequential {@code Stream} and whose up-streams are sequential {@code Streams} as well. // * Because error happening in the operations executed by parallel stream will stop iteration on that {@Stream}, so the down-streams won't be able to continue. // * // * @param predicate // * @param supplierForFallbackValue // * @return // */ // @Beta // @SequentialOnly // @IntermediateOp // public abstract Stream onErrorReturn(Predicate predicate, Supplier supplierForFallbackValue); // // /** // * This method should be only applied sequential {@code Stream} and whose up-streams are sequential {@code Streams} as well. // * Because error happening in the operations executed by parallel stream will stop iteration on that {@Stream}, so the down-streams won't be able to continue. // * // * @param predicate // * @param mapperForFallbackValue // * @param maxErrorCountToStop // * @return // */ // @Beta // @SequentialOnly // @IntermediateOp // public abstract Stream onErrorReturn(Predicate predicate, Function mapperForFallbackValue, // int maxErrorCountToStop); // // /** // * // * @return // */ // @Beta // @SequentialOnly // @IntermediateOp // public abstract Stream onErrorStop(); // @Beta // @ParallelSupported // @TerminalOp // public abstract void foreach(java.util.function.Consumer action); /** * * * @param * @param action * @throws E */ @ParallelSupported @TerminalOp public abstract void forEach(Throwables.Consumer action) throws E; /** * * * @param * @param action * @throws E */ @ParallelSupported @TerminalOp public abstract void forEachIndexed(Throwables.IndexedConsumer action) throws E; /** * Iterate and execute {@code action} until the flag is set true. * Flag can only be set after at least one element is iterated and executed by {@code action}. * * @param * @param action the second parameter is a flag to break the for-each loop. * Set it to {@code true} to break the loop if you don't want to continue the {@code action}. * Iteration on this stream will also be stopped when this flag is set to {@code true}. * @throws E * @see {@link #forEachUntil(MutableBoolean, Throwables.Consumer)} */ @Beta @ParallelSupported @TerminalOp public abstract void forEachUntil(Throwables.BiConsumer action) throws E; /** * Iterate and execute {@code action} until {@code flagToBreak} is set true. * If {@code flagToBreak} is set to true at the begin, there will be no element iterated from stream before this stream is stopped and closed. * * @param * @param flagToBreak a flag to break the for-each loop. * Set it to {@code true} to break the loop if you don't want to continue the {@code action}. * Iteration on this stream will also be stopped when this flag is set to {@code true}. * @param action * @throws E * @see {@link #forEachUntil(Throwables.BiConsumer)} */ @Beta @ParallelSupported @TerminalOp public abstract void forEachUntil(MutableBoolean flagToBreak, Throwables.Consumer action) throws E; /** * * * @param * @param * @param action * @param onComplete * @throws E * @throws E2 */ @ParallelSupported @TerminalOp public abstract void forEach(Throwables.Consumer action, Throwables.Runnable onComplete) throws E, E2; /** * * * @param * @param * @param * @param flatMapper * @param action * @throws E * @throws E2 */ @ParallelSupported @TerminalOp public abstract void forEach( final Throwables.Function, E> flatMapper, final Throwables.BiConsumer action) throws E, E2; /** * * * @param * @param * @param * @param * @param * @param flatMapper * @param flatMapper2 * @param action * @throws E * @throws E2 * @throws E3 */ @ParallelSupported @TerminalOp public abstract void forEach( final Throwables.Function, E> flatMapper, final Throwables.Function, E2> flatMapper2, final Throwables.TriConsumer action) throws E, E2, E3; /** * * * @param * @param action * @throws E */ @ParallelSupported @TerminalOp public abstract void forEachPair(final Throwables.BiConsumer action) throws E; /** * * @param * @param action * @param increment * @throws E */ @ParallelSupported @TerminalOp public abstract void forEachPair(final Throwables.BiConsumer action, final int increment) throws E; /** * * * @param * @param action * @throws E */ @ParallelSupported @TerminalOp public abstract void forEachTriple(final Throwables.TriConsumer action) throws E; /** * * @param * @param action * @param increment * @throws E */ @ParallelSupported @TerminalOp public abstract void forEachTriple(final Throwables.TriConsumer action, final int increment) throws E; /** * * * @param * @param predicate * @return * @throws E */ @ParallelSupported @TerminalOp public abstract boolean anyMatch(Throwables.Predicate predicate) throws E; /** * * * @param * @param predicate * @return * @throws E */ @ParallelSupported @TerminalOp public abstract boolean allMatch(Throwables.Predicate predicate) throws E; /** * * * @param * @param predicate * @return * @throws E */ @ParallelSupported @TerminalOp public abstract boolean noneMatch(Throwables.Predicate predicate) throws E; /** * * * @param * @param atLeast * @param atMost * @param predicate * @return * @throws E */ @ParallelSupported @TerminalOp public abstract boolean nMatch(long atLeast, long atMost, Throwables.Predicate predicate) throws E; /** * Returns the first element matched by {@code predicateForFirst} if found, Otherwise an empty {@code Optional} will be returned. * * @param * @param predicate * @return * @throws E */ @ParallelSupported @TerminalOp public abstract Optional findFirst(Throwables.Predicate predicate) throws E; /** * Returns the last element matched by {@code predicateForFirst} if found, Otherwise an empty {@code Optional} will be returned. * *
* Consider using: {@code stream.reversed().findFirst(predicate)} for better performance if possible. * * @param * @param predicate * @return * @throws E */ @ParallelSupported @TerminalOp public abstract Optional findLast(Throwables.Predicate predicate) throws E; /** * Returns any element matched by {@code predicateForFirst} if found, Otherwise an empty {@code Optional} will be returned. * It's same as {@code findFirst} and always returns the first element matched by {@code predicateForFirst} if found in sequential stream. * In parallel stream, it may have better performance than {@code findFirst}. * * @param * @param predicate * @return * @throws E */ @ParallelSupported @TerminalOp public abstract Optional findAny(Throwables.Predicate predicate) throws E; /** * Returns the first element matched by {@code predicateForFirst} if found or the first element if this stream is not empty * Otherwise an empty {@code Optional} will be returned. * * @param * @param predicateForFirst * @return * @throws E */ @ParallelSupported @TerminalOp public abstract Optional findFirstOrAny(Throwables.Predicate predicateForFirst) throws E; /** * Returns the first element matched by {@code predicateForFirst} if found or any element matched by {@code predicateForAny} (If this is a sequential stream, it will always be the first element matched by {@code predicateForAny}). * Otherwise an empty {@code Optional} will be returned. * * @param * @param * @param predicateForFirst * @param predicateForAny * @return * @throws E * @throws E2 */ @ParallelSupported @TerminalOp public abstract Optional findFirstOrAny(Throwables.Predicate predicateForFirst, Throwables.Predicate predicateForAny) throws E, E2; /** * Returns the first element matched by {@code predicateForFirst} if found or the last element if this stream is not empty * Otherwise an empty {@code Optional} will be returned. * * @param * @param predicateForFirst * @return * @throws E */ @ParallelSupported @TerminalOp public abstract Optional findFirstOrLast(Throwables.Predicate predicateForFirst) throws E; /** * * * @param * @param * @param predicateForFirst * @param predicateForLast * @return * @throws E * @throws E2 */ @Beta @SequentialOnly @TerminalOp public abstract Optional findFirstOrLast(Throwables.Predicate predicateForFirst, Throwables.Predicate predicateForLast) throws E, E2; /** *
* This method only runs sequentially, even in parallel stream. * * @param * @param * @param * @param init * @param predicateForFirst * @param predicateForLast * @return * @throws E * @throws E2 */ @Beta @SequentialOnly @TerminalOp public abstract Optional findFirstOrLast(final U init, final Throwables.BiPredicate predicateForFirst, final Throwables.BiPredicate predicateForLast) throws E, E2; /** *
* This method only runs sequentially, even in parallel stream. * * @param * @param * @param * @param preFunc * @param predicateForFirst * @param predicateForLast * @return * @throws E * @throws E2 */ @Beta @SequentialOnly @TerminalOp public abstract Optional findFirstOrLast(final Function preFunc, final Throwables.BiPredicate predicateForFirst, final Throwables.BiPredicate predicateForLast) throws E, E2; /** * * * @param a * @return */ @SequentialOnly @TerminalOp public abstract boolean containsAll(T... a); /** * * * @param c * @return */ @SequentialOnly @TerminalOp public abstract boolean containsAll(Collection c); /** * * * @param a * @return */ @SequentialOnly @TerminalOp public abstract boolean containsAny(T... a); /** * * * @param c * @return */ @SequentialOnly @TerminalOp public abstract boolean containsAny(Collection c); /** * * * @param
* @param generator * @return */ @SequentialOnly @TerminalOp public abstract A[] toArray(IntFunction generator); /** * * * @param * @param * @param * @param * @param keyMapper * @param valueMapper * @return * @throws E * @throws E2 * @see Collectors#toMap(Function, Function) */ @SuppressWarnings("deprecation") @ParallelSupported @TerminalOp public ImmutableMap toImmutableMap(Throwables.Function keyMapper, Throwables.Function valueMapper) throws E, E2 { return ImmutableMap.wrap(toMap(keyMapper, valueMapper)); } /** * * * @param * @param * @param * @param * @param keyMapper * @param valueMapper * @param mergeFunction * @return * @throws E * @throws E2 * @see Collectors#toMap(Function, Function) */ @SuppressWarnings("deprecation") @ParallelSupported @TerminalOp public ImmutableMap toImmutableMap(Throwables.Function keyMapper, Throwables.Function valueMapper, BinaryOperator mergeFunction) throws E, E2 { return ImmutableMap.wrap(toMap(keyMapper, valueMapper, mergeFunction)); } /** * * * @param * @param * @param * @param * @param keyMapper * @param valueMapper * @return * @throws E * @throws E2 * @see Collectors#toMap(Function, Function) */ @ParallelSupported @TerminalOp public abstract Map toMap(Throwables.Function keyMapper, Throwables.Function valueMapper) throws E, E2; /** * * * @param * @param * @param * @param * @param keyMapper * @param valueMapper * @param mergeFunction * @return * @throws E * @throws E2 * @see Collectors#toMap(Function, Function, BinaryOperator) */ @ParallelSupported @TerminalOp public abstract Map toMap(Throwables.Function keyMapper, Throwables.Function valueMapper, BinaryOperator mergeFunction) throws E, E2; /** * * * @param * @param * @param * @param * @param * @param keyMapper * @param valueMapper * @param mapFactory * @return * @throws E * @throws E2 * @see Collectors#toMap(Function, Function, Supplier) */ @ParallelSupported @TerminalOp public abstract , E extends Exception, E2 extends Exception> M toMap(Throwables.Function keyMapper, Throwables.Function valueMapper, Supplier mapFactory) throws E, E2; /** * * * @param * @param * @param * @param * @param * @param keyMapper * @param valueMapper * @param mergeFunction * @param mapFactory * @return * @throws E * @throws E2 * @see Collectors#toMap(Function, Function, BinaryOperator, Supplier) */ @ParallelSupported @TerminalOp public abstract , E extends Exception, E2 extends Exception> M toMap(Throwables.Function keyMapper, Throwables.Function valueMapper, BinaryOperator mergeFunction, Supplier mapFactory) throws E, E2; // /** // * // * @param keyMapper // * @param downstream // * @return // * @see #groupTo(Throwables.Function, Collector) // * @deprecated replaced by {@code groupTo} // */ // @Deprecated // @ParallelSupported // @TerminalOp // public final Map toMap(Throwables.Function keyMapper, // final Collector downstream) throws E { // return groupTo(keyMapper, downstream); // } // // /** // * // * @param keyMapper // * @param downstream // * @param mapFactory // * @return // * @see #groupTo(Throwables.Function, Collector, Supplier) // * @deprecated replaced by {@code groupTo} // */ // @Deprecated // @ParallelSupported // @TerminalOp // public final , E extends Exception> M toMap(Throwables.Function keyMapper, // final Collector downstream, final Supplier mapFactory) throws E { // return groupTo(keyMapper, downstream, mapFactory); // } // // /** // * // * @param keyMapper // * @param valueMapper // * @param downstream // * @return // * @see #groupTo(Throwables.Function, Throwables.Function, Collector) // * @deprecated replaced by {@code groupTo} // */ // @Deprecated // @ParallelSupported // @TerminalOp // public final Map toMap(Throwables.Function keyMapper, // Throwables.Function valueMapper, final Collector downstream) throws E, E2 { // return groupTo(keyMapper, valueMapper, downstream); // } // // /** // * // * @param keyMapper // * @param valueMapper // * @param downstream // * @param mapFactory // * @return // * @see #groupTo(Throwables.Function, Throwables.Function, Collector, Supplier) // * @deprecated replaced by {@code groupTo} // */ // @Deprecated // @ParallelSupported // @TerminalOp // public final , E extends Exception, E2 extends Exception> M toMap(Throwables.Function keyMapper, // Throwables.Function valueMapper, final Collector downstream, final Supplier mapFactory) // throws E, E2 { // return groupTo(keyMapper, valueMapper, downstream, mapFactory); // } /** * * * @param * @param * @param keyMapper * @return * @throws E * @see Collectors#groupingBy(Function) */ @ParallelSupported @TerminalOp public abstract Map> groupTo(Throwables.Function keyMapper) throws E; /** * * * @param * @param * @param * @param keyMapper * @param mapFactory * @return * @throws E * @see Collectors#groupingBy(Function, Supplier) */ @ParallelSupported @TerminalOp public abstract >, E extends Exception> M groupTo(Throwables.Function keyMapper, final Supplier mapFactory) throws E; /** * * * @param * @param * @param * @param * @param keyMapper * @param valueMapper * @return * @throws E * @throws E2 */ @ParallelSupported @TerminalOp public abstract Map> groupTo(Throwables.Function keyMapper, Throwables.Function valueMapper) throws E, E2; /** * * * @param * @param * @param * @param * @param * @param keyMapper * @param valueMapper * @param mapFactory * @return * @throws E * @throws E2 * @see Collectors#toMultimap(Function, Function, Supplier) */ @ParallelSupported @TerminalOp public abstract >, E extends Exception, E2 extends Exception> M groupTo( Throwables.Function keyMapper, Throwables.Function valueMapper, Supplier mapFactory) throws E, E2; /** * * * @param * @param * @param * @param * @param keyMapper * @param downstream * @return * @throws E * @see Collectors#groupingBy(Function, Collector) */ @ParallelSupported @TerminalOp public abstract Map groupTo(Throwables.Function keyMapper, final Collector downstream) throws E; /** * * * @param * @param * @param * @param * @param * @param keyMapper * @param downstream * @param mapFactory * @return * @throws E * @see Collectors#groupingBy(Function, Collector, Supplier) */ @ParallelSupported @TerminalOp public abstract , E extends Exception> M groupTo(Throwables.Function keyMapper, final Collector downstream, final Supplier mapFactory) throws E; /** * * * @param * @param * @param * @param * @param * @param * @param keyMapper * @param valueMapper * @param downstream * @return * @throws E * @throws E2 * @see Collectors#groupingBy(Function, Collector) */ @ParallelSupported @TerminalOp public abstract Map groupTo(Throwables.Function keyMapper, Throwables.Function valueMapper, final Collector downstream) throws E, E2; /** * * * @param * @param * @param * @param * @param * @param * @param * @param keyMapper * @param valueMapper * @param downstream * @param mapFactory * @return * @throws E * @throws E2 * @see Collectors#groupingBy(Function, Collector, Supplier) */ @ParallelSupported @TerminalOp public abstract , E extends Exception, E2 extends Exception> M groupTo( Throwables.Function keyMapper, Throwables.Function valueMapper, final Collector downstream, final Supplier mapFactory) throws E, E2; // /** // * // * @param // * @param // * @param flatKeyMapper // * @return // * @throws E // */ // @ParallelSupported // @TerminalOp // public abstract Map> flatGroupTo(Throwables.Function, E> flatKeyMapper) // throws E; // // /** // * // * @param // * @param // * @param // * @param flatKeyMapper // * @param mapFactory // * @return // * @throws E // */ // @ParallelSupported // @TerminalOp // public abstract >, E extends Exception> M flatGroupTo( // final Throwables.Function, E> flatKeyMapper, final Supplier mapFactory) throws E; // // /** // * // * @param // * @param // * @param // * @param // * @param flatKeyMapper // * @param valueMapper // * @return // * @throws E // * @throws E2 // */ // @ParallelSupported // @TerminalOp // public abstract Map> flatGroupTo( // Throwables.Function, E> flatKeyMapper, // Throwables.BiFunction valueMapper) throws E, E2; // // /** // * // * @param // * @param // * @param // * @param // * @param // * @param flatKeyMapper // * @param valueMapper // * @param mapFactory // * @return // * @throws E // * @throws E2 // */ // @ParallelSupported // @TerminalOp // public abstract >, E extends Exception, E2 extends Exception> M flatGroupTo( // Throwables.Function, E> flatKeyMapper, // Throwables.BiFunction valueMapper, Supplier mapFactory) throws E, E2; /** * * @param * @param * @param flatKeyMapper * @return * @throws E */ @ParallelSupported @TerminalOp public abstract Map> flatGroupTo(Throwables.Function, E> flatKeyMapper) throws E; /** * * @param * @param * @param * @param flatKeyMapper * @param mapFactory * @return * @throws E */ @ParallelSupported @TerminalOp public abstract >, E extends Exception> M flatGroupTo( final Throwables.Function, E> flatKeyMapper, final Supplier mapFactory) throws E; /** * * @param * @param * @param * @param * @param flatKeyMapper * @param valueMapper * @return * @throws E * @throws E2 */ @ParallelSupported @TerminalOp public abstract Map> flatGroupTo( Throwables.Function, E> flatKeyMapper, Throwables.BiFunction valueMapper) throws E, E2; /** * * @param * @param * @param * @param * @param * @param flatKeyMapper * @param valueMapper * @param mapFactory * @return * @throws E * @throws E2 */ @ParallelSupported @TerminalOp public abstract >, E extends Exception, E2 extends Exception> M flatGroupTo( Throwables.Function, E> flatKeyMapper, Throwables.BiFunction valueMapper, Supplier mapFactory) throws E, E2; // /** // * // * @param // * @param // * @param // * @param // * @param flatKeyMapper // * @param downstream // * @return // * @throws E // */ // @ParallelSupported // @TerminalOp // public abstract Map flatGroupTo(final Throwables.Function, E> flatKeyMapper, // final Collector downstream) throws E; // // /** // * // * @param // * @param // * @param // * @param // * @param // * @param flatKeyMapper // * @param downstream // * @param mapFactory // * @return // * @throws E // */ // @ParallelSupported // @TerminalOp // public abstract , E extends Exception> M flatGroupTo( // final Throwables.Function, E> flatKeyMapper, final Collector downstream, // final Supplier mapFactory) throws E; // // /** // * // * @param // * @param // * @param // * @param // * @param // * @param // * @param flatKeyMapper // * @param valueMapper // * @param downstream // * @return // * @throws E // * @throws E2 // */ // @ParallelSupported // @TerminalOp // public abstract Map flatGroupTo( // final Throwables.Function, E> flatKeyMapper, // final Throwables.BiFunction valueMapper, final Collector downstream) throws E, E2; // // /** // * // * @param // * @param // * @param // * @param // * @param // * @param // * @param // * @param flatKeyMapper // * @param valueMapper // * @param downstream // * @param mapFactory // * @return // * @throws E // * @throws E2 // */ // @ParallelSupported // @TerminalOp // public abstract , E extends Exception, E2 extends Exception> M flatGroupTo( // final Throwables.Function, E> flatKeyMapper, // final Throwables.BiFunction valueMapper, final Collector downstream, // final Supplier mapFactory) throws E, E2; /** * * @param * @param * @param * @param * @param flatKeyMapper * @param downstream * @return * @throws E */ @ParallelSupported @TerminalOp public abstract Map flatGroupTo( final Throwables.Function, E> flatKeyMapper, final Collector downstream) throws E; /** * * @param * @param * @param * @param * @param * @param flatKeyMapper * @param downstream * @param mapFactory * @return * @throws E */ @ParallelSupported @TerminalOp public abstract , E extends Exception> M flatGroupTo( final Throwables.Function, E> flatKeyMapper, final Collector downstream, final Supplier mapFactory) throws E; /** * * @param * @param * @param * @param * @param * @param * @param flatKeyMapper * @param valueMapper * @param downstream * @return * @throws E * @throws E2 */ @ParallelSupported @TerminalOp public abstract Map flatGroupTo( final Throwables.Function, E> flatKeyMapper, final Throwables.BiFunction valueMapper, final Collector downstream) throws E, E2; /** * * @param * @param * @param * @param * @param * @param * @param * @param flatKeyMapper * @param valueMapper * @param downstream * @param mapFactory * @return * @throws E * @throws E2 */ @ParallelSupported @TerminalOp public abstract , E extends Exception, E2 extends Exception> M flatGroupTo( final Throwables.Function, E> flatKeyMapper, final Throwables.BiFunction valueMapper, final Collector downstream, final Supplier mapFactory) throws E, E2; /** * * * @param * @param predicate * @return * @throws E * @see Collectors#partitioningBy(Predicate) */ @ParallelSupported @TerminalOp public abstract Map> partitionTo(final Throwables.Predicate predicate) throws E; /** * * * @param * @param * @param * @param predicate * @param downstream * @return * @throws E * @see Collectors#partitioningBy(Predicate, Collector) */ @ParallelSupported @TerminalOp public abstract Map partitionTo(final Throwables.Predicate predicate, final Collector downstream) throws E; /** * * * @param * @param * @param keyMapper * @return * @throws E * @see Collectors#toMultimap(Function, Function) */ @ParallelSupported @TerminalOp public abstract ListMultimap toMultimap(Throwables.Function keyMapper) throws E; /** * * * @param * @param * @param * @param * @param keyMapper * @param mapFactory * @return * @throws E * @see Collectors#toMultimap(Function, Function, Supplier) */ @ParallelSupported @TerminalOp public abstract , M extends Multimap, E extends Exception> M toMultimap( Throwables.Function keyMapper, Supplier mapFactory) throws E; /** * * * @param * @param * @param * @param * @param keyMapper * @param valueMapper * @return * @throws E * @throws E2 * @see Collectors#toMultimap(Function, Function) */ @ParallelSupported @TerminalOp public abstract ListMultimap toMultimap(Throwables.Function keyMapper, Throwables.Function valueMapper) throws E, E2; /** * * * @param * @param * @param * @param * @param * @param * @param keyMapper * @param valueMapper * @param mapFactory * @return * @throws E * @throws E2 * @see Collectors#toMultimap(Function, Function, Supplier) */ @ParallelSupported @TerminalOp public abstract , M extends Multimap, E extends Exception, E2 extends Exception> M toMultimap( Throwables.Function keyMapper, Throwables.Function valueMapper, Supplier mapFactory) throws E, E2; /** * 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 bean or map. * * @return * @see {@link N#newDataSet(Collection)} */ @SequentialOnly @TerminalOp public abstract DataSet toDataSet(); /** * 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 bean or map. * * @param columnNames * @return * @see {@link N#newDataSet(Collection, Collection)} */ @SequentialOnly @TerminalOp public abstract DataSet toDataSet(final List columnNames); /** * * * @param joiner * @return */ @SequentialOnly @TerminalOp public abstract String join(final Joiner joiner); /** * This method will always run sequentially, even in parallel stream. * * @param * @param accumulator * @return * @throws E * @see #reduce(BinaryOperator) */ @SequentialOnly @TerminalOp public abstract Optional foldLeft(Throwables.BinaryOperator accumulator) throws E; /** * This method will always run sequentially, even in parallel stream. * * @param * @param * @param identity * @param accumulator * @return * @throws E * @see #reduce(Object, BiFunction, BinaryOperator) */ @SequentialOnly @TerminalOp public abstract U foldLeft(U identity, Throwables.BiFunction accumulator) throws E; /** * This method will always run sequentially, even in parallel stream. * * @param * @param accumulator * @return * @throws E * @see #reduce(BinaryOperator) */ @SequentialOnly @TerminalOp public abstract Optional foldRight(Throwables.BinaryOperator accumulator) throws E; /** * This method will always run sequentially, even in parallel stream. * * @param * @param * @param identity * @param accumulator * @return * @throws E * @see #reduce(Object, BiFunction, BinaryOperator) */ @SequentialOnly @TerminalOp public abstract U foldRight(U identity, Throwables.BiFunction accumulator) throws E; /** * * * @param * @param accumulator * @return * @throws E * @see #foldLeft(Throwables.BinaryOperator) */ @ParallelSupported @TerminalOp public abstract Optional reduce(Throwables.BinaryOperator accumulator) throws E; /** * * * @param * @param identity * @param accumulator * @return * @throws E * @see #foldLeft(Object, Throwables.BiFunction) */ @ParallelSupported @TerminalOp public T reduce(T identity, Throwables.BinaryOperator accumulator) throws E { return reduce(identity, accumulator, accumulator); } /** * * * @param * @param * @param identity * @param accumulator * @param combiner * @return * @throws E * @see #foldLeft(Object, Throwables.BiFunction) */ @ParallelSupported @TerminalOp public abstract U reduce(U identity, Throwables.BiFunction accumulator, Throwables.BinaryOperator combiner) throws E; /** * * * @param * @param accumulator * @param conditionToBreak the input parameter is the return value of {@code accumulator}, not the element from this Stream. * Returns {@code true} to break the loop if you don't want to continue the {@code action}. * Iteration on this stream will also be stopped when this flag is set to {@code true}. * @return * @throws E * @see #foldLeft(Throwables.BinaryOperator) */ @Beta @ParallelSupported @TerminalOp public abstract Optional reduceUntil(Throwables.BinaryOperator accumulator, Throwables.Predicate conditionToBreak) throws E; /** * * * @param * @param identity * @param accumulator * @param conditionToBreak the input parameter is the return value of {@code accumulator}, not the element from this Stream. * Returns {@code true} to break the loop if you don't want to continue the {@code action}. * Iteration on this stream will also be stopped when this flag is set to {@code true}. * @return * @throws E * @see #foldLeft(Object, Throwables.BiFunction) */ @Beta @ParallelSupported @TerminalOp public T reduceUntil(T identity, Throwables.BinaryOperator accumulator, Throwables.Predicate conditionToBreak) throws E { return reduceUntil(identity, accumulator, accumulator, conditionToBreak); } /** * * * @param * @param * @param identity * @param accumulator * @param combiner * @param conditionToBreak the input parameter is the return value of {@code accumulator}, not the element from this Stream. * Returns {@code true} to break the loop if you don't want to continue the {@code action}. * Iteration on this stream will also be stopped when this flag is set to {@code true}. * @return * @throws E * @see #foldLeft(Object, Throwables.BiFunction) */ @Beta @ParallelSupported @TerminalOp public abstract U reduceUntil(U identity, Throwables.BiFunction accumulator, Throwables.BinaryOperator combiner, Throwables.Predicate conditionToBreak) throws E; /** * * @param if {@code R} is {@code Map/Collection/StringBuilder/Multiset/LongMultiset/Multimap/BooleanList/IntList/.../DoubleList}, It's not required to specified {@code combiner}. * Otherwise, {@code combiner} must be specified. * @param supplier * @param accumulator * @param combiner * @return * @see #collect(Supplier, BiConsumer) */ @ParallelSupported @TerminalOp public abstract R collect(Supplier supplier, BiConsumer accumulator, BiConsumer combiner); /** * Only call this method when the returned type {@code R} is one types: {@code Collection/Map/StringBuilder/Multiset/LongMultiset/Multimap/BooleanList/IntList/.../DoubleList}. * Otherwise, please call {@link #collect(Supplier, BiConsumer, BiConsumer)}. * * @param * @param supplier * @param accumulator * @return * @see #collect(Supplier, BiConsumer, BiConsumer) */ @ParallelSupported @TerminalOp public abstract R collect(Supplier supplier, BiConsumer accumulator); /** * * * @param * @param * @param collector * @return */ @ParallelSupported @TerminalOp public abstract R collect(Collector collector); /** * * * @param * @param * @param * @param * @param downstream * @param func * @return * @throws E */ @ParallelSupported @TerminalOp public abstract RR collectAndThen(Collector downstream, Throwables.Function func) throws E; /** * * * @param * @param * @param func * @return * @throws E */ @SequentialOnly @TerminalOp public abstract R toListAndThen(Throwables.Function, ? extends R, E> func) throws E; /** * * * @param * @param * @param func * @return * @throws E */ @SequentialOnly @TerminalOp public abstract R toSetAndThen(Throwables.Function, ? extends R, E> func) throws E; /** * * * @param * @param * @param * @param supplier * @param func * @return * @throws E */ @SequentialOnly @TerminalOp public abstract , E extends Exception> R toCollectionAndThen(Supplier supplier, Throwables.Function func) throws E; /** * * * @param comparator * @return */ @ParallelSupported @TerminalOp public abstract Optional min(Comparator comparator); /** * * * @param keyMapper * @return */ @ParallelSupported @TerminalOp @SuppressWarnings("rawtypes") public Optional minBy(final Function keyMapper) { final Comparator comparator = Fn.comparingBy(keyMapper); return min(comparator); } /** * * * @param comparator * @return */ @ParallelSupported @TerminalOp public abstract List minAll(Comparator comparator); /** * * * @param comparator * @return */ @ParallelSupported @TerminalOp public abstract Optional max(Comparator comparator); /** * * * @param keyMapper * @return */ @ParallelSupported @TerminalOp @SuppressWarnings("rawtypes") public Optional maxBy(final Function keyMapper) { final Comparator comparator = Fn.comparingBy(keyMapper); return max(comparator); } /** * * * @param comparator * @return */ @ParallelSupported @TerminalOp public abstract List maxAll(Comparator comparator); /** * * @param k * @param comparator * @return Optional.empty() if there is no element or count less than k, otherwise the kth largest element. */ @ParallelSupported @TerminalOp public abstract Optional kthLargest(int k, Comparator comparator); /** * * * @param mapper * @return */ @ParallelSupported @TerminalOp public abstract long sumInt(ToIntFunction mapper); /** * * * @param mapper * @return */ @ParallelSupported @TerminalOp public abstract long sumLong(ToLongFunction mapper); /** * * * @param mapper * @return */ @ParallelSupported @TerminalOp public abstract double sumDouble(ToDoubleFunction mapper); /** * * * @param mapper * @return */ @ParallelSupported @TerminalOp public abstract OptionalDouble averageInt(ToIntFunction mapper); /** * * * @param mapper * @return */ @ParallelSupported @TerminalOp public abstract OptionalDouble averageLong(ToLongFunction mapper); /** * * * @param mapper * @return */ @ParallelSupported @TerminalOp public abstract OptionalDouble averageDouble(ToDoubleFunction mapper); /** * * * @param comparator * @return */ @SequentialOnly @TerminalOp public abstract Optional> percentiles(Comparator comparator); /** * * * @return */ @SequentialOnly @TerminalOp public abstract boolean hasDuplicates(); // It won't work for findFirst/only/anyMatch... // @ParallelSupported // @TerminalOp // public abstract Pair countAnd(Throwables.Function, ? extends R, E> terminalAction) throws E; /** *
     * 
     * Stream.of(1, 2, 3).combinations().forEach(Fn.println());
     * // output
     * []
     * [1]
     * [2]
     * [3]
     * [1, 2]
     * [1, 3]
     * [2, 3]
     * [1, 2, 3]
     * 
     * 
* * @return */ @SequentialOnly @IntermediateOp public abstract Stream> combinations(); /** *
     * 
     * Stream.of(1, 2, 3).combinations(2).forEach(Fn.println());
     * // output
     * [1, 2]
     * [1, 3]
     * [2, 3]
     * 
     * 
* * @param len * @return */ @SequentialOnly @IntermediateOp public abstract Stream> combinations(int len); /** * It's same as {@code N.cartesianProduct(N.repeat(toList(), len))} if {@code repeat} is {@code true}. *
     * 
     * Stream.of(1, 2, 3).combinations(2, true).forEach(Fn.println());
     * // output
     * [1, 1]
     * [1, 2]
     * [1, 3]
     * [2, 1]
     * [2, 2]
     * [2, 3]
     * [3, 1]
     * [3, 2]
     * [3, 3]
     * 
     * 
* * @param len * @param repeat * @return */ @SequentialOnly @IntermediateOp public abstract Stream> combinations(int len, boolean repeat); /** *
     * 
     * Stream.of(1, 2, 3).permutations().forEach(Fn.println());
     * // output
     * [1, 2, 3]
     * [1, 3, 2]
     * [3, 1, 2]
     * [3, 2, 1]
     * [2, 3, 1]
     * [2, 1, 3]
     * 
     * 
* * @return */ @SequentialOnly @IntermediateOp public abstract Stream> permutations(); /** *
     * 
     * Stream.of(1, 2, 3).orderedPermutations().forEach(Fn.println());
     * // output
     * [1, 2, 3]
     * [1, 3, 2]
     * [2, 1, 3]
     * [2, 3, 1]
     * [3, 1, 2]
     * [3, 2, 1]
     * 
     * 
* * @return */ @SequentialOnly @IntermediateOp public abstract Stream> orderedPermutations(); /** * * * @param comparator * @return */ @SequentialOnly @IntermediateOp public abstract Stream> orderedPermutations(Comparator comparator); /** * * * @param cs * @return */ @SequentialOnly @IntermediateOp @SafeVarargs public final Stream> cartesianProduct(Collection... cs) { return cartesianProduct(Arrays.asList(cs)); } /** * * * @param cs * @return */ @SequentialOnly @IntermediateOp public abstract Stream> cartesianProduct(Collection> cs); /** * Intersect with the specified Collection by the values mapped by mapper. * * @param * @param mapper * @param c * @return * @see N#intersection(Collection, Collection) */ @ParallelSupported @IntermediateOp public abstract Stream intersection(Function mapper, Collection c); /** * Except with the specified Collection by the values mapped by mapper. * * @param * @param mapper * @param c * @return * @see N#difference(Collection, Collection) */ @ParallelSupported @IntermediateOp public abstract Stream difference(Function mapper, Collection c); /** * * @param defaultValue * @return * @see #appendIfEmpty(Object...) */ @SequentialOnly @IntermediateOp public final Stream defaultIfEmpty(final T defaultValue) { return appendIfEmpty(defaultValue); } // /** // * // * @param defaultValues // * @return // * @see #appendIfEmpty(Object...) // */ // @SequentialOnly // @IntermediateOp // public final Stream defaultIfEmpty(final Collection defaultValues) { // return appendIfEmpty(defaultValues); // } /** * * @param supplier * @return * @see #appendIfEmpty(Supplier) */ @SequentialOnly @IntermediateOp public final Stream defaultIfEmpty(final Supplier> supplier) { return appendIfEmpty(supplier); } // @SequentialOnly // public abstract Stream appendAlll(Collection> cs); /** * * * @param a * @return */ @SequentialOnly @IntermediateOp @SafeVarargs public final Stream prepend(T... a) { return prepend(Arrays.asList(a)); } /** * * * @param c * @return */ @SequentialOnly @IntermediateOp public abstract Stream prepend(Collection c); /** * * * @param a * @return */ @SequentialOnly @IntermediateOp @SafeVarargs public final Stream append(T... a) { return append(Arrays.asList(a)); } /** * * * @param c * @return */ @SequentialOnly @IntermediateOp public abstract Stream append(Collection c); // @SequentialOnly // public abstract Stream appendAlll(Collection> cs); // @SequentialOnly // public abstract Stream prependAlll(Collection> cs); /** * * * @param a * @return */ @SequentialOnly @IntermediateOp @SafeVarargs public final Stream appendIfEmpty(T... a) { return appendIfEmpty(Arrays.asList(a)); } /** * * * @param c * @return */ @SequentialOnly @IntermediateOp public abstract Stream appendIfEmpty(Collection c); // /** // * Returns a reusable stream which can be repeatedly used. // * // *
// * All elements will be loaded to memory. // * // * @param generator // * @return // */ // @SequentialOnly // public abstract Stream cached(IntFunction generator); // /** // * The Stream will be closed finally, no matter it's empty or not. // * // * @param func // * @return // */ // @Beta // public abstract Optional applyIfNotEmpty(Try.Function, ? extends R, E> func) throws E; // // /** // * The Stream will be closed finally, no matter it's empty or not. // * // * @param action // * // */ // @Beta // public abstract void acceptIfNotEmpty(Try.Consumer, E> action) throws E; /** * * * @return */ @SequentialOnly @IntermediateOp @TerminalOpTriggered public abstract Stream> rollup(); /** * Returns a new Stream with elements from a temporary queue which is filled by reading the elements from this Stream asynchronously with a new thread. * Default queue size is 64. *
* Mostly it's for {@code read-write with different threads} mode. * * @return * @see #buffered() */ @SequentialOnly @IntermediateOp public abstract Stream buffered(); /** * Returns a new Stream with elements from a temporary queue which is filled by reading the elements from this Stream asynchronously with a new thread. *
* Mostly it's for {@code read-write with different threads} mode. * @param bufferSize * @return * @see #buffered(int) */ @SequentialOnly @IntermediateOp public abstract Stream buffered(int bufferSize); // /** // * Returns a new Stream with elements from a temporary queue which is filled by reading the elements from this Stream asynchronously with a new thread. // * Default queue size is 64. // * // * @return // */ // @SequentialOnly // @IntermediateOp // public Stream buffered() { // return queued(); // } // // /** // * Returns a new Stream with elements from a temporary queue which is filled by reading the elements from this Stream asynchronously with a new thread. // * // * @param bufferSize // * @return // */ // @SequentialOnly // @IntermediateOp // public Stream buffered(final int bufferSize) { // return queued(bufferSize); // } // /** // * // * @param b // * @param nextSelector first parameter is selected if Nth.FIRST is returned, otherwise the second parameter is selected. // * @return // * @deprecated replaced by {@code mergeWith(Stream, BiFunction)} // * @see #mergeWith(Stream, BiFunction) // */ // @Deprecated // @SequentialOnly // @IntermediateOp // public Stream merge(final Stream b, final BiFunction nextSelector) { // return mergeWith(b, nextSelector); // } /** * * @param b * @param nextSelector first parameter is selected if Nth.FIRST is returned, otherwise the second parameter is selected. * @return */ @SequentialOnly @IntermediateOp public abstract Stream mergeWith(final Collection b, final BiFunction nextSelector); /** * * @param b * @param nextSelector first parameter is selected if Nth.FIRST is returned, otherwise the second parameter is selected. * @return */ @SequentialOnly @IntermediateOp public abstract Stream mergeWith(final Stream b, final BiFunction nextSelector); /** * * * @param * @param * @param b * @param zipFunction * @return */ @ParallelSupported @IntermediateOp public abstract Stream zipWith(final Collection b, final BiFunction zipFunction); /** * * * @param * @param * @param b * @param valueForNoneA * @param valueForNoneB * @param zipFunction * @return */ @ParallelSupported @IntermediateOp public abstract Stream zipWith(final Collection b, final T valueForNoneA, final T2 valueForNoneB, final BiFunction zipFunction); /** * * * @param * @param * @param * @param b * @param c * @param zipFunction * @return */ @ParallelSupported @IntermediateOp public abstract Stream zipWith(final Collection b, final Collection c, final TriFunction zipFunction); /** * * * @param * @param * @param * @param b * @param c * @param valueForNoneA * @param valueForNoneB * @param valueForNoneC * @param zipFunction * @return */ @ParallelSupported @IntermediateOp public abstract Stream zipWith(final Collection b, final Collection c, final T valueForNoneA, final T2 valueForNoneB, final T3 valueForNoneC, final TriFunction zipFunction); /** * * * @param * @param * @param b * @param zipFunction * @return */ @ParallelSupported @IntermediateOp public abstract Stream zipWith(final Stream b, final BiFunction zipFunction); /** * * * @param * @param * @param b * @param valueForNoneA * @param valueForNoneB * @param zipFunction * @return */ @ParallelSupported @IntermediateOp public abstract Stream zipWith(final Stream b, final T valueForNoneA, final T2 valueForNoneB, final BiFunction zipFunction); /** * * * @param * @param * @param * @param b * @param c * @param zipFunction * @return */ @ParallelSupported @IntermediateOp public abstract Stream zipWith(final Stream b, final Stream c, final TriFunction zipFunction); /** * * * @param * @param * @param * @param b * @param c * @param valueForNoneA * @param valueForNoneB * @param valueForNoneC * @param zipFunction * @return */ @ParallelSupported @IntermediateOp public abstract Stream zipWith(final Stream b, final Stream c, final T valueForNoneA, final T2 valueForNoneB, final T3 valueForNoneC, final TriFunction zipFunction); /** * * * @param file * @return * @throws IOException */ @SequentialOnly @TerminalOp public abstract long persist(File file) throws IOException; /** * * * @param header * @param tail * @param file * @return * @throws IOException */ @SequentialOnly @TerminalOp public abstract long persist(String header, String tail, File file) throws IOException; /** * toCSV: *
     * final JSONSerializationConfig jsc = JSC.create().setBracketRootValue(false);
     * final Throwables.Function toLine = it -> N.toJSON(it, jsc);
     * stream.persist(toLine, header, outputFile);
     * 
* * @param toLine * @param file * @return * @throws IOException */ @SequentialOnly @TerminalOp public abstract long persist(Throwables.Function toLine, File file) throws IOException; /** * * * @param toLine * @param header * @param tail * @param file * @return * @throws IOException */ @SequentialOnly @TerminalOp public abstract long persist(Throwables.Function toLine, String header, String tail, File file) throws IOException; /** * * * @param toLine * @param os * @return * @throws IOException */ @SequentialOnly @TerminalOp public abstract long persist(Throwables.Function toLine, OutputStream os) throws IOException; /** * toCSV: *
     * final JSONSerializationConfig jsc = JSC.create().setBracketRootValue(false);
     * final Throwables.Function toLine = it -> N.toJSON(it, jsc);
     * stream.persist(toLine, header, outputFile);
     * 
* * @param toLine * @param writer * @return * @throws IOException */ @SequentialOnly @TerminalOp public abstract long persist(Throwables.Function toLine, Writer writer) throws IOException; /** * * * @param toLine * @param header * @param tail * @param writer * @return * @throws IOException */ @SequentialOnly @TerminalOp public abstract long persist(Throwables.Function toLine, String header, String tail, Writer writer) throws IOException; /** * * @param writeLine * @param file * @return * @throws IOException * @see {@link Fnn#writeCSVLine()} */ @SequentialOnly @TerminalOp public abstract long persist(final Throwables.BiConsumer writeLine, final File file) throws IOException; /** * * @param writeLine * @param header * @param tail * @param file * @return * @throws IOException * @see {@link Fnn#writeCSVLine()} */ @SequentialOnly @TerminalOp public abstract long persist(final Throwables.BiConsumer writeLine, final String header, final String tail, final File file) throws IOException; /** * * @param writeLine * @param writer * @return * @throws IOException * @see {@link Fnn#writeCSVLine()} */ @SequentialOnly @TerminalOp public abstract long persist(final Throwables.BiConsumer writeLine, final Writer writer) throws IOException; /** * * @param writeLine * @param header * @param tail * @param writer * @return * @throws IOException * @see {@link Fnn#writeCSVLine()} */ @SequentialOnly @TerminalOp public abstract long persist(final Throwables.BiConsumer writeLine, final String header, final String tail, final Writer writer) throws IOException; /** * * @param conn * @param insertSQL * @param batchSize * @param batchIntervalInMillis * @param stmtSetter * @return * @throws SQLException */ @SequentialOnly @TerminalOp public abstract long persist(final Connection conn, final String insertSQL, final int batchSize, final long batchIntervalInMillis, final Throwables.BiConsumer stmtSetter) throws SQLException; /** * * @param stmt * @param batchSize * @param batchIntervalInMillis * @param stmtSetter * @return * @throws SQLException */ @SequentialOnly @TerminalOp public abstract long persist(final PreparedStatement stmt, final int batchSize, final long batchIntervalInMillis, final Throwables.BiConsumer stmtSetter) throws SQLException; /** * Each line in the output file/Writer is an array of JSON String without root bracket. * * @param file * @return * @throws IOException */ @SequentialOnly @TerminalOp public abstract long persistToCSV(File file) throws IOException; /** * Each line in the output file/Writer is an array of JSON String without root bracket. * * @param csvHeaders * @param file * @return * @throws IOException */ @SequentialOnly @TerminalOp public abstract long persistToCSV(Collection csvHeaders, File file) throws IOException; /** * Each line in the output file/Writer is an array of JSON String without root bracket. * * @param os * @return * @throws IOException */ @SequentialOnly @TerminalOp public abstract long persistToCSV(OutputStream os) throws IOException; /** * Each line in the output file/Writer is an array of JSON String without root bracket. * * @param csvHeaders * @param os * @return * @throws IOException */ @SequentialOnly @TerminalOp public abstract long persistToCSV(Collection csvHeaders, OutputStream os) throws IOException; /** * Each line in the output file/Writer is an array of JSON String without root bracket. * * @param writer * @return * @throws IOException */ @SequentialOnly @TerminalOp public abstract long persistToCSV(Writer writer) throws IOException; /** * Each line in the output file/Writer is an array of JSON String without root bracket. * * @param csvHeaders * @param writer * @return * @throws IOException */ @SequentialOnly @TerminalOp public abstract long persistToCSV(Collection csvHeaders, Writer writer) throws IOException; /** * Remember to close this Stream after the iteration is done, if needed. * * @return */ @SequentialOnly @IntermediateOp public abstract java.util.stream.Stream toJdkStream(); /** * * * @param * @return */ @Beta @SequentialOnly @IntermediateOp public ExceptionalStream checked() { return CheckedStream. of(this); } /** * * @param * @param exceptionType * @return */ @Beta @SequentialOnly @IntermediateOp public ExceptionalStream checked(final Class exceptionType) { return CheckedStream. of(this, exceptionType); } /** * Remember to close this Stream after the iteration is done, if needed. * * @return */ @SequentialOnly @Override public ObjIterator iterator() { assertNotClosed(); if (!isEmptyCloseHandlers(closeHandlers) && logger.isWarnEnabled()) { logger.warn("### Remember to close " + ClassUtil.getSimpleClassName(getClass())); } return iteratorEx(); } abstract ObjIteratorEx iteratorEx(); /** * Temporarily switch the stream to parallel stream for operation {@code op} and then switch back to sequence stream. *
* {@code split(bufferSize).flatMap(s -> op.apply(s)).sequential()} * * @param * @param maxThreadNum * @param bufferSize * @param op * @return */ @Beta @IntermediateOp public Stream sps(final int maxThreadNum, final int bufferSize, final Function, ? extends Stream> op) { assertNotClosed(); final int executorNumForVirtualThread = 0; if (this.isParallel() && maxThreadNum == maxThreadNum() && executorNumForVirtualThread == executorNumForVirtualThread()) { return split(bufferSize).flatMap(op::apply).sequential(); } else { final AsyncExecutor asyncExecutor = asyncExecutor(); final int checkedMaxThreadNum = checkMaxThreadNum(maxThreadNum, executorNumForVirtualThread, asyncExecutor); final int checkedVirtualTaskNum = checkExecutorNumForVirtualThread(checkedMaxThreadNum, executorNumForVirtualThread); return split(bufferSize).parallel(checkedMaxThreadNum, checkedVirtualTaskNum, splitor(), asyncExecutor, cancelUncompletedThreads()) .flatMap(op::apply) .sequential(); } } /** * Temporarily switch the stream to parallel stream for operation {@code filter} and then switch back to sequence stream. *
* {@code stream().parallel().filter(predicate).sequence()} * * @param predicate * @return * @see #sps(Function) */ @Beta @IntermediateOp public Stream spsFilter(final Predicate predicate) { return sps(s -> s.filter(predicate)); } /** * Temporarily switch the stream to parallel stream for operation {@code map} and then switch back to sequence stream. *
* {@code stream().parallel().map(mapper).sequence()} * @param * @param mapper * @return * @see #sps(Function) */ @Beta @IntermediateOp public Stream spsMap(final Function mapper) { return sps(s -> s.map(mapper)); } /** * Temporarily switch the stream to parallel stream for operation {@code flatMap} and then switch back to sequence stream. *
* {@code stream().parallel().flatMap(mapper).sequence()} * * @param * @param mapper * @return * @see #sps(Function) */ @Beta @IntermediateOp public Stream spsFlatMap(final Function> mapper) { return sps(s -> s.flatMap(mapper)); } /** * Temporarily switch the stream to parallel stream for operation {@code flatMap} and then switch back to sequence stream. *
* {@code stream().parallel().flatmap(mapper).sequence()} * * @param * @param mapper * @return * @see #sps(Function) */ @Beta @IntermediateOp public Stream spsFlatmap(final Function> mapper) { return sps(s -> s.flatmap(mapper)); } /** * Temporarily switch the stream to parallel stream for operation {@code onEach} and then switch back to sequence stream. *
* {@code stream().parallel().onEach(action).sequence()} * * @param action * @return * @see #sps(Function) */ @Beta @IntermediateOp public Stream spsOnEach(final Consumer action) { return sps(s -> s.onEach(action)); } /** * Temporarily switch the stream to parallel stream for operation {@code filter} and then switch back to sequence stream. *
* {@code stream().parallel(maxThreadNum).filter(predicate).sequence()} * * @param maxThreadNum * @param predicate * @return * @see #sps(int, Function) */ @Beta @IntermediateOp public Stream spsFilter(final int maxThreadNum, final Predicate predicate) { return sps(maxThreadNum, s -> s.filter(predicate)); } /** * Temporarily switch the stream to parallel stream for operation {@code map} and then switch back to sequence stream. *
* {@code stream().parallel(maxThreadNum).map(mapper).sequence()} * * @param * @param maxThreadNum * @param mapper * @return * @see #sps(int, Function) */ @Beta @IntermediateOp public Stream spsMap(final int maxThreadNum, final Function mapper) { return sps(maxThreadNum, s -> s.map(mapper)); } /** * Temporarily switch the stream to parallel stream for operation {@code flatMap} and then switch back to sequence stream. *
* {@code stream().parallel(maxThreadNum).flatMap(mapper).sequence()} * * @param * @param maxThreadNum * @param mapper * @return * @see #sps(int, Function) */ @Beta @IntermediateOp public Stream spsFlatMap(final int maxThreadNum, final Function> mapper) { return sps(maxThreadNum, s -> s.flatMap(mapper)); } /** * Temporarily switch the stream to parallel stream for operation {@code flatMap} and then switch back to sequence stream. *
* {@code stream().parallel(maxThreadNum).flatmap(mapper).sequence()} * * @param * @param maxThreadNum * @param mapper * @return * @see #sps(int, Function) */ @Beta @IntermediateOp public Stream spsFlatmap(final int maxThreadNum, final Function> mapper) { return sps(maxThreadNum, s -> s.flatmap(mapper)); } /** * Temporarily switch the stream to parallel stream for operation {@code onEach} and then switch back to sequence stream. *
* {@code stream().parallel(maxThreadNum).onEach(action).sequence()} * * @param maxThreadNum * @param action * @return * @see #sps(int, Function) */ @Beta @IntermediateOp public Stream spsOnEach(final int maxThreadNum, final Consumer action) { return sps(maxThreadNum, s -> s.onEach(action)); } /** * Temporarily switch the stream to parallel stream for operation {@code filter} and then switch back to sequence stream. *
* {@code split(bufferSize).flatMap(s -> s.filter(predicate)).sequential()} * * @param maxThreadNum * @param bufferSize * @param predicate * @return * @see #sps(int, int, Function) */ @Beta @IntermediateOp public Stream spsFilter(final int maxThreadNum, final int bufferSize, final Predicate predicate) { return sps(maxThreadNum, bufferSize, s -> s.filter(predicate)); } /** * Temporarily switch the stream to parallel stream for operation {@code map} and then switch back to sequence stream. *
* {@code split(bufferSize).flatMap(s -> s.map(mapper)).sequential()} * * @param * @param maxThreadNum * @param bufferSize * @param mapper * @return * @see #sps(int, int, Function) */ @Beta @IntermediateOp public Stream spsMap(final int maxThreadNum, final int bufferSize, final Function mapper) { return sps(maxThreadNum, bufferSize, s -> s.map(mapper)); } /** * Temporarily switch the stream to parallel stream for operation {@code flatMap} and then switch back to sequence stream. *
* {@code split(bufferSize).flatMap(s -> s.flatMap(mapper)).sequential()} * * @param * @param maxThreadNum * @param bufferSize * @param mapper * @return * @see #sps(int, int, Function) */ @Beta @IntermediateOp public Stream spsFlatMap(final int maxThreadNum, final int bufferSize, final Function> mapper) { return sps(maxThreadNum, bufferSize, s -> s.flatMap(mapper)); } /** * Temporarily switch the stream to parallel stream for operation {@code flatMap} and then switch back to sequence stream. *
* {@code split(bufferSize).flatMap(s -> s.flatmap(mapper)).sequential()} * * @param * @param maxThreadNum * @param bufferSize * @param mapper * @return * @see #sps(int, int, Function) */ @Beta @IntermediateOp public Stream spsFlatmap(final int maxThreadNum, final int bufferSize, final Function> mapper) { return sps(maxThreadNum, bufferSize, s -> s.flatmap(mapper)); } /** * Temporarily switch the stream to parallel stream for operation {@code onEach} and then switch back to sequence stream. *
* {@code split(bufferSize).flatMap(s -> s.onEach(action)).sequential()} * * @param maxThreadNum * @param bufferSize * @param action * @return * @see #sps(int, int, Function) */ @Beta @IntermediateOp public Stream spsOnEach(final int maxThreadNum, final int bufferSize, final Consumer action) { return sps(maxThreadNum, bufferSize, s -> s.onEach(action)); } /** * Temporarily switch the stream to parallel stream for operation {@code filter} and then switch back to sequence stream. *
* {@code stream().parallel().filterE(predicate).sequence()} * * @param predicate * @return * @see #sps(Function) */ @Beta @IntermediateOp public Stream spsFilterE(final Throwables.Predicate predicate) { return sps(s -> s.filterE(predicate)); } /** * Temporarily switch the stream to parallel stream for operation {@code map} and then switch back to sequence stream. *
* {@code stream().parallel().mapE(mapper).sequence()} * @param * @param mapper * @return * @see #sps(Function) */ @Beta @IntermediateOp public Stream spsMapE(final Throwables.Function mapper) { return sps(s -> s.mapE(mapper)); } /** * Temporarily switch the stream to parallel stream for operation {@code flatMap} and then switch back to sequence stream. *
* {@code stream().parallel().flatMapE(mapper).sequence()} * * @param * @param mapper * @return * @see #sps(Function) */ @Beta @IntermediateOp public Stream spsFlatMapE(final Throwables.Function, ? extends Exception> mapper) { return sps(s -> s.flatMapE(mapper)); } /** * Temporarily switch the stream to parallel stream for operation {@code flatMap} and then switch back to sequence stream. *
* {@code stream().parallel().flatmapE(mapper).sequence()} * * @param * @param mapper * @return * @see #sps(Function) */ @Beta @IntermediateOp public Stream spsFlatmapE(final Throwables.Function, ? extends Exception> mapper) { return sps(s -> s.flatmapE(mapper)); } /** * Temporarily switch the stream to parallel stream for operation {@code onEach} and then switch back to sequence stream. *
* {@code stream().parallel().onEachE(action).sequence()} * * @param action * @return * @see #sps(Function) */ @Beta @IntermediateOp public Stream spsOnEachE(final Throwables.Consumer action) { return sps(s -> s.onEachE(action)); } /** * Temporarily switch the stream to parallel stream for operation {@code filter} and then switch back to sequence stream. *
* {@code stream().parallel().filterE(predicate).sequence()} * * @param maxThreadNum * @param predicate * @return * @see #sps(Function) */ @Beta @IntermediateOp public Stream spsFilterE(final int maxThreadNum, final Throwables.Predicate predicate) { return sps(maxThreadNum, s -> s.filterE(predicate)); } /** * Temporarily switch the stream to parallel stream for operation {@code map} and then switch back to sequence stream. *
* {@code stream().parallel().mapE(mapper).sequence()} * @param * @param maxThreadNum * @param mapper * @return * @see #sps(Function) */ @Beta @IntermediateOp public Stream spsMapE(final int maxThreadNum, final Throwables.Function mapper) { return sps(maxThreadNum, s -> s.mapE(mapper)); } /** * Temporarily switch the stream to parallel stream for operation {@code flatMap} and then switch back to sequence stream. *
* {@code stream().parallel().flatMapE(mapper).sequence()} * * @param * @param maxThreadNum * @param mapper * @return * @see #sps(Function) */ @Beta @IntermediateOp public Stream spsFlatMapE(final int maxThreadNum, final Throwables.Function, ? extends Exception> mapper) { return sps(maxThreadNum, s -> s.flatMapE(mapper)); } /** * Temporarily switch the stream to parallel stream for operation {@code flatMap} and then switch back to sequence stream. *
* {@code stream().parallel().flatmapE(mapper).sequence()} * * @param * @param maxThreadNum * @param mapper * @return * @see #sps(Function) */ @Beta @IntermediateOp public Stream spsFlatmapE(final int maxThreadNum, final Throwables.Function, ? extends Exception> mapper) { return sps(maxThreadNum, s -> s.flatmapE(mapper)); } /** * Temporarily switch the stream to parallel stream for operation {@code onEach} and then switch back to sequence stream. *
* {@code stream().parallel().onEachE(action).sequence()} * * @param maxThreadNum * @param action * @return * @see #sps(Function) */ @Beta @IntermediateOp public Stream spsOnEachE(final int maxThreadNum, final Throwables.Consumer action) { return sps(maxThreadNum, s -> s.onEachE(action)); } /** * Temporarily switch the stream to Jdk parallel stream for operation {@code ops} and then switch back to sequence stream. *
* {@code stream.(switchToJdkStream).parallel().ops(map/filter/...).(switchBack).sequence()} * * @param * @param op * @return */ @Beta @IntermediateOp public Stream sjps(Function, ? extends java.util.stream.Stream> op) { if (this.isParallel()) { return newStream(((java.util.stream.Stream) op.apply(this.toJdkStream())).iterator(), false, null).sequential(); //NOSONAR } else { return newStream(((java.util.stream.Stream) op.apply(this.toJdkStream().parallel())).iterator(), false, null); } } // No performance improvement. // /** // * Temporarily switch the stream to Jdk parallel stream for operation {@code ops} and then switch back to sequence stream. // *
// * {@code stream.(switchToJdkStream).parallel().ops(map/filter/...).(switchBack).sequence()} // * // * @param // * @param op // * @return // */ // @Beta // @IntermediateOp // public IntStream sjpis(Function, ? extends java.util.stream.IntStream> op) { // if (this.isParallel()) { // return IntStream.of(op.apply(this.toJdkStream())).sequential(); // } else { // return IntStream.of(op.apply(this.toJdkStream().parallel())).sequential(); // } // } // // /** // * Temporarily switch the stream to Jdk parallel stream for operation {@code ops} and then switch back to sequence stream. // *
// * {@code stream.(switchToJdkStream).parallel().ops(map/filter/...).(switchBack).sequence()} // * // * @param // * @param op // * @return // */ // @Beta // @IntermediateOp // public LongStream sjpls(Function, ? extends java.util.stream.LongStream> op) { // if (this.isParallel()) { // return LongStream.of(op.apply(this.toJdkStream())).sequential(); // } else { // return LongStream.of(op.apply(this.toJdkStream().parallel())).sequential(); // } // } // // /** // * Temporarily switch the stream to Jdk parallel stream for operation {@code ops} and then switch back to sequence stream. // *
// * {@code stream.(switchToJdkStream).parallel().ops(map/filter/...).(switchBack).sequence()} // * // * @param // * @param op // * @return // */ // @Beta // @IntermediateOp // public DoubleStream sjpds(Function, ? extends java.util.stream.DoubleStream> op) { // if (this.isParallel()) { // return DoubleStream.of(op.apply(this.toJdkStream())).sequential(); // } else { // return DoubleStream.of(op.apply(this.toJdkStream().parallel())).sequential(); // } // } /** * * @param predicate * @return * @see Fn#pp(Throwables.Predicate) */ @Beta @ParallelSupported @IntermediateOp public Stream filterE(final Throwables.Predicate predicate) { return filter(Fn.pp(predicate)); } /** * * @param * @param mapper * @return * @see Fn#ff(Throwables.Function) */ @Beta @ParallelSupported @IntermediateOp public Stream mapE(final Throwables.Function mapper) { return map(Fn.ff(mapper)); } /** * * @param * @param mapper * @return * @see Fn#ff(Throwables.Function) */ @Beta @ParallelSupported @IntermediateOp public Stream flatMapE(final Throwables.Function, ? extends Exception> mapper) { return flatMap(Fn.ff(mapper)); } /** * * @param * @param mapper * @return * @see Fn#ff(Throwables.Function) */ @Beta @ParallelSupported @IntermediateOp public Stream flatmapE(final Throwables.Function, ? extends Exception> mapper) { return flatmap(Fn.ff(mapper)); } /** * * * @param action * @return * @see Fn#cc(Throwables.Consumer) */ @Beta @ParallelSupported @IntermediateOp public Stream onEachE(final Throwables.Consumer action) { return onEach(Fn.cc(action)); } /** * To reduce the memory footprint, Only one instance of DisposableEntry is created, * and the same entry instance is returned and set with different keys/values during iteration of the returned stream. * The elements only can be retrieved one by one, can't be modified or saved. * The returned Stream doesn't support the operations which require two or more elements at the same time: (e.g. sort/distinct/pairMap/slidingMap/sliding/split/toList/toSet/...). * , and can't be parallel stream. * Operations: filter/map/toMap/groupBy/groupTo/... are supported. * * @param * @param * @param keyMapper * @param valueMapper * @return * @see DisposableEntry * @see NoCachingNoUpdating * @deprecated */ @Beta @SequentialOnly @Deprecated public Stream> mapToDisposableEntry(final Function keyMapper, final Function valueMapper) { assertNotClosed(); checkState(!isParallel(), "mapToDisposableEntry can't be applied to parallel stream"); final Function> mapper = new Function<>() { private final EntryStream.ReusableEntry entry = new EntryStream.ReusableEntry<>(); @Override public DisposableEntry apply(T t) { entry.set(keyMapper.apply(t), valueMapper.apply(t)); return entry; } }; return map(mapper); } // ################################################################################################################################# // ################################################################################################################################# /** * * @param terminalAction a terminal operation should be called. * @return */ @Beta @TerminalOp public ContinuableFuture asyncRun(final Throwables.Consumer, ? extends Exception> terminalAction) { checkArgNotNull(terminalAction, "terminalAction"); return ContinuableFuture.run(() -> terminalAction.accept(Stream.this)); } /** * * @param terminalAction a terminal operation should be called. * @param executor * @return */ @Beta @TerminalOp public ContinuableFuture asyncRun(final Throwables.Consumer, ? extends Exception> terminalAction, final Executor executor) { checkArgNotNull(terminalAction, "terminalAction"); checkArgNotNull(executor, "executor"); return ContinuableFuture.run(() -> terminalAction.accept(Stream.this), executor); } /** * * * @param * @param terminalAction a terminal operation should be called. * @return */ @Beta @TerminalOp public ContinuableFuture asyncCall(final Throwables.Function, R, ? extends Exception> terminalAction) { checkArgNotNull(terminalAction, "terminalAction"); return ContinuableFuture.call(() -> terminalAction.apply(Stream.this)); } /** * * * @param * @param terminalAction a terminal operation should be called. * @param executor * @return */ @Beta @TerminalOp public ContinuableFuture asyncCall(final Throwables.Function, R, ? extends Exception> terminalAction, final Executor executor) { checkArgNotNull(terminalAction, "terminalAction"); checkArgNotNull(executor, "executor"); return ContinuableFuture.call(() -> terminalAction.apply(Stream.this), executor); } /** * * * @param * @return */ public static Stream empty() { return new ArrayStream<>((T[]) N.EMPTY_OBJECT_ARRAY, true, NATURAL_COMPARATOR, null); } /** * * * @param * @param e * @return */ public static Stream just(final T e) { return of(N.asArray(e)); } /** * Returns an empty {@code Stream} if the specified {@code t} is null. * * @param * @param e * @return */ public static Stream ofNullable(final T e) { return e == null ? Stream. empty() : of(e); } /** * * * @param * @param a * @return */ @SafeVarargs public static Stream of(final T... a) { return N.isNullOrEmpty(a) ? (Stream) empty() : of(a, 0, a.length); } /** * * * @param * @param a * @param startIndex * @param endIndex * @return */ public static Stream of(final T[] a, final int startIndex, final int endIndex) { return N.isNullOrEmpty(a) && (startIndex == 0 && endIndex == 0) ? (Stream) empty() : new ArrayStream<>(a, startIndex, endIndex); } /** * * * @param * @param c * @return */ public static Stream of(final Collection c) { return N.isNullOrEmpty(c) ? (Stream) empty() : of(c, 0, c.size()); } /** * * * @param * @param c * @param startIndex * @param endIndex * @return */ public static Stream of(final Collection c, int startIndex, int endIndex) { N.checkFromToIndex(startIndex, endIndex, N.size(c)); if (N.isNullOrEmpty(c) && (startIndex == 0 && endIndex == 0)) { return empty(); } // return new CollectionStream(c); // return new ArrayStream((T[]) c.toArray()); // faster if (isListElementDataFieldGettable && listElementDataField != null && c.getClass().equals(ArrayList.class)) { T[] a = null; try { a = (T[]) listElementDataField.get(c); } catch (Throwable e) { // ignore; isListElementDataFieldGettable = false; } if (a != null) { return of(a, startIndex, endIndex); } } if (startIndex == 0 && endIndex == c.size()) { // return (c.size() > 10 && (c.size() < 1000 || (c.size() < 100000 && c instanceof ArrayList))) ? streamOf((T[]) c.toArray()) : c.stream(); return of(ObjIteratorEx.of(c)); } else { return of(ObjIteratorEx.of(c), startIndex, endIndex); } } /** * * * @param * @param * @param map * @return */ public static Stream> of(final Map map) { if (N.isNullOrEmpty(map)) { return empty(); } @SuppressWarnings("rawtypes") final Map tmp = (Map) map; return Stream.of(tmp.entrySet()); } /** * * * @param * @param iterable * @return */ public static Stream of(final Iterable iterable) { if (iterable == null) { return empty(); } if (iterable instanceof Collection) { return of((Collection) iterable); } else { return of(iterable.iterator()); } } /** * * * @param * @param iterator * @return */ public static Stream of(final Iterator iterator) { if (iterator == null) { return empty(); } return new IteratorStream<>(iterator); } /** * * @param c * @param startIndex * @param endIndex * @return */ static Stream of(final Iterator iterator, int startIndex, int endIndex) { if (iterator == null && (startIndex == 0 && endIndex == 0)) { return empty(); } if (startIndex < 0 || endIndex < startIndex) { throw new IllegalArgumentException("startIndex(" + startIndex + ") or endIndex(" + endIndex + ") is invalid"); } return Stream. of(iterator).skip(startIndex).limit(endIndex - startIndex); //NOSONAR } /** * * * @param * @param stream * @return */ public static Stream of(final java.util.stream.Stream stream) { if (stream == null) { return empty(); } return of(new ObjIteratorEx() { private Iterator iter = null; @Override public boolean hasNext() { if (iter == null) { iter = stream.iterator(); } return iter.hasNext(); } @Override public T next() { if (iter == null) { iter = stream.iterator(); } return iter.next(); } @Override public long count() { return iter == null ? stream.count() : super.count(); } @Override public void advance(long n) { if (iter == null) { iter = stream.skip(n).iterator(); } else { super.advance(n); } } @Override public Object[] toArray() { return iter == null ? stream.toArray() : super.toArray(); } @Override public
A[] toArray(final A[] a) { return iter == null ? stream.toArray(value -> a) : super.toArray(a); } }).__(s -> stream.isParallel() ? s.parallel() : s.sequential()).onClose(stream::close); } /** * * * @param * @param enumeration * @return */ public static Stream of(final Enumeration enumeration) { if (enumeration == null) { return empty(); } return new IteratorStream<>(new ObjIteratorEx() { @Override public boolean hasNext() { return enumeration.hasMoreElements(); } @Override public T next() { return enumeration.nextElement(); } }); } /** * * * @param a * @return */ public static Stream of(final boolean[] a) { if (N.isNullOrEmpty(a)) { return empty(); } return of(a, 0, a.length); } /** * * * @param a * @param fromIndex * @param toIndex * @return */ public static Stream of(final boolean[] a, final int fromIndex, final int toIndex) { N.checkFromToIndex(fromIndex, toIndex, N.len(a)); if (N.isNullOrEmpty(a)) { return empty(); } return of(new ObjIteratorEx() { private int cursor = fromIndex; @Override public boolean hasNext() { return cursor < toIndex; } @Override public Boolean next() { if (cursor >= toIndex) { throw new NoSuchElementException(); } return a[cursor++]; } @Override public long count() { return toIndex - cursor; //NOSONAR } @Override public void advance(long n) { cursor = n < toIndex - cursor ? cursor + (int) n : toIndex; } @Override public A[] toArray(A[] a2) { a2 = a2.length >= toIndex - cursor ? a2 : (A[]) N.newArray(a2.getClass().getComponentType(), toIndex - cursor); for (int i = 0, len = toIndex - cursor; i < len; i++) { a2[i] = (A) Boolean.valueOf(a[cursor++]); } return a2; } }); } /** * * * @param a * @return */ public static Stream of(char[] a) { if (N.isNullOrEmpty(a)) { return empty(); } return of(a, 0, a.length); } /** * * * @param a * @param fromIndex * @param toIndex * @return */ public static Stream of(final char[] a, final int fromIndex, final int toIndex) { N.checkFromToIndex(fromIndex, toIndex, N.len(a)); if (N.isNullOrEmpty(a)) { return empty(); } return of(new ObjIteratorEx() { private int cursor = fromIndex; @Override public boolean hasNext() { return cursor < toIndex; } @Override public Character next() { if (cursor >= toIndex) { throw new NoSuchElementException(); } return a[cursor++]; } @Override public long count() { return toIndex - cursor; //NOSONAR } @Override public void advance(long n) { cursor = n < toIndex - cursor ? cursor + (int) n : toIndex; } @Override public A[] toArray(A[] a2) { a2 = a2.length >= toIndex - cursor ? a2 : (A[]) N.newArray(a2.getClass().getComponentType(), toIndex - cursor); for (int i = 0, len = toIndex - cursor; i < len; i++) { a2[i] = (A) Character.valueOf(a[cursor++]); } return a2; } }); } /** * * * @param a * @return */ public static Stream of(byte[] a) { if (N.isNullOrEmpty(a)) { return empty(); } return of(a, 0, a.length); } /** * * * @param a * @param fromIndex * @param toIndex * @return */ public static Stream of(final byte[] a, final int fromIndex, final int toIndex) { N.checkFromToIndex(fromIndex, toIndex, N.len(a)); if (N.isNullOrEmpty(a)) { return empty(); } return of(new ObjIteratorEx() { private int cursor = fromIndex; @Override public boolean hasNext() { return cursor < toIndex; } @Override public Byte next() { if (cursor >= toIndex) { throw new NoSuchElementException(); } return a[cursor++]; } @Override public long count() { return toIndex - cursor; //NOSONAR } @Override public void advance(long n) { cursor = n < toIndex - cursor ? cursor + (int) n : toIndex; } @Override public A[] toArray(A[] a2) { a2 = a2.length >= toIndex - cursor ? a2 : (A[]) N.newArray(a2.getClass().getComponentType(), toIndex - cursor); for (int i = 0, len = toIndex - cursor; i < len; i++) { a2[i] = (A) Byte.valueOf(a[cursor++]); } return a2; } }); } /** * * * @param a * @return */ public static Stream of(short[] a) { if (N.isNullOrEmpty(a)) { return empty(); } return of(a, 0, a.length); } /** * * * @param a * @param fromIndex * @param toIndex * @return */ public static Stream of(final short[] a, final int fromIndex, final int toIndex) { N.checkFromToIndex(fromIndex, toIndex, N.len(a)); if (N.isNullOrEmpty(a)) { return empty(); } return of(new ObjIteratorEx() { private int cursor = fromIndex; @Override public boolean hasNext() { return cursor < toIndex; } @Override public Short next() { if (cursor >= toIndex) { throw new NoSuchElementException(); } return a[cursor++]; } @Override public long count() { return toIndex - cursor; //NOSONAR } @Override public void advance(long n) { cursor = n < toIndex - cursor ? cursor + (int) n : toIndex; } @Override public A[] toArray(A[] a2) { a2 = a2.length >= toIndex - cursor ? a2 : (A[]) N.newArray(a2.getClass().getComponentType(), toIndex - cursor); for (int i = 0, len = toIndex - cursor; i < len; i++) { a2[i] = (A) Short.valueOf(a[cursor++]); } return a2; } }); } /** * * * @param a * @return */ public static Stream of(int[] a) { if (N.isNullOrEmpty(a)) { return empty(); } return of(a, 0, a.length); } /** * * * @param a * @param fromIndex * @param toIndex * @return */ public static Stream of(final int[] a, final int fromIndex, final int toIndex) { N.checkFromToIndex(fromIndex, toIndex, N.len(a)); if (N.isNullOrEmpty(a)) { return empty(); } return of(new ObjIteratorEx() { private int cursor = fromIndex; @Override public boolean hasNext() { return cursor < toIndex; } @Override public Integer next() { if (cursor >= toIndex) { throw new NoSuchElementException(); } return a[cursor++]; } @Override public long count() { return toIndex - cursor; //NOSONAR } @Override public void advance(long n) { cursor = n < toIndex - cursor ? cursor + (int) n : toIndex; } @Override public A[] toArray(A[] a2) { a2 = a2.length >= toIndex - cursor ? a2 : (A[]) N.newArray(a2.getClass().getComponentType(), toIndex - cursor); for (int i = 0, len = toIndex - cursor; i < len; i++) { a2[i] = (A) Integer.valueOf(a[cursor++]); } return a2; } }); } /** * * * @param a * @return */ public static Stream of(long[] a) { if (N.isNullOrEmpty(a)) { return empty(); } return of(a, 0, a.length); } /** * * * @param a * @param fromIndex * @param toIndex * @return */ public static Stream of(final long[] a, final int fromIndex, final int toIndex) { N.checkFromToIndex(fromIndex, toIndex, N.len(a)); if (N.isNullOrEmpty(a)) { return empty(); } return of(new ObjIteratorEx() { private int cursor = fromIndex; @Override public boolean hasNext() { return cursor < toIndex; } @Override public Long next() { if (cursor >= toIndex) { throw new NoSuchElementException(); } return a[cursor++]; } @Override public long count() { return toIndex - cursor; //NOSONAR } @Override public void advance(long n) { cursor = n < toIndex - cursor ? cursor + (int) n : toIndex; } @Override public A[] toArray(A[] a2) { a2 = a2.length >= toIndex - cursor ? a2 : (A[]) N.newArray(a2.getClass().getComponentType(), toIndex - cursor); for (int i = 0, len = toIndex - cursor; i < len; i++) { a2[i] = (A) Long.valueOf(a[cursor++]); } return a2; } }); } /** * * * @param a * @return */ public static Stream of(float[] a) { if (N.isNullOrEmpty(a)) { return empty(); } return of(a, 0, a.length); } /** * * * @param a * @param fromIndex * @param toIndex * @return */ public static Stream of(final float[] a, final int fromIndex, final int toIndex) { N.checkFromToIndex(fromIndex, toIndex, N.len(a)); if (N.isNullOrEmpty(a)) { return empty(); } return of(new ObjIteratorEx() { private int cursor = fromIndex; @Override public boolean hasNext() { return cursor < toIndex; } @Override public Float next() { if (cursor >= toIndex) { throw new NoSuchElementException(); } return a[cursor++]; } @Override public long count() { return toIndex - cursor; //NOSONAR } @Override public void advance(long n) { cursor = n < toIndex - cursor ? cursor + (int) n : toIndex; } @Override public A[] toArray(A[] a2) { a2 = a2.length >= toIndex - cursor ? a2 : (A[]) N.newArray(a2.getClass().getComponentType(), toIndex - cursor); for (int i = 0, len = toIndex - cursor; i < len; i++) { a2[i] = (A) Float.valueOf(a[cursor++]); } return a2; } }); } /** * * * @param a * @return */ public static Stream of(double[] a) { if (N.isNullOrEmpty(a)) { return empty(); } return of(a, 0, a.length); } /** * * * @param a * @param fromIndex * @param toIndex * @return */ public static Stream of(final double[] a, final int fromIndex, final int toIndex) { N.checkFromToIndex(fromIndex, toIndex, N.len(a)); if (N.isNullOrEmpty(a)) { return empty(); } return of(new ObjIteratorEx() { private int cursor = fromIndex; @Override public boolean hasNext() { return cursor < toIndex; } @Override public Double next() { if (cursor >= toIndex) { throw new NoSuchElementException(); } return a[cursor++]; } @Override public long count() { return toIndex - cursor; //NOSONAR } @Override public void advance(long n) { cursor = n < toIndex - cursor ? cursor + (int) n : toIndex; } @Override public A[] toArray(A[] a2) { a2 = a2.length >= toIndex - cursor ? a2 : (A[]) N.newArray(a2.getClass().getComponentType(), toIndex - cursor); for (int i = 0, len = toIndex - cursor; i < len; i++) { a2[i] = (A) Double.valueOf(a[cursor++]); } return a2; } }); } /** * * * @param * @param op * @return */ public static Stream of(final Optional op) { return op == null || !op.isPresent() ? Stream. empty() : Stream.of(op.get()); //NOSONAR } /** * * * @param * @param op * @return */ public static Stream of(final java.util.Optional op) { return op == null || !op.isPresent() ? Stream. empty() : Stream.of(op.get()); //NOSONAR } /** * * * @param * @param map * @return */ public static Stream ofKeys(final Map map) { if (N.isNullOrEmpty(map)) { return Stream.empty(); } return of(map.keySet()); } /** * * * @param * @param * @param map * @param valueFilter * @return */ public static Stream ofKeys(final Map map, final Predicate valueFilter) { if (N.isNullOrEmpty(map)) { return StreamEx.empty(); } return EntryStream. of(map).filterByValue(valueFilter).keys(); } /** * * * @param * @param * @param map * @param filter * @return */ public static Stream ofKeys(final Map map, final BiPredicate filter) { if (N.isNullOrEmpty(map)) { return StreamEx.empty(); } return EntryStream. of(map).filter(filter).keys(); } /** * * * @param * @param map * @return */ public static Stream ofValues(final Map map) { if (N.isNullOrEmpty(map)) { return Stream.empty(); } return of(map.values()); } /** * * * @param * @param * @param map * @param keyFilter * @return */ public static Stream ofValues(final Map map, final Predicate keyFilter) { if (N.isNullOrEmpty(map)) { return Stream.empty(); } return EntryStream. of(map).filterByKey(keyFilter).values(); } /** * * * @param * @param * @param map * @param filter * @return */ public static Stream ofValues(final Map map, final BiPredicate filter) { if (N.isNullOrEmpty(map)) { return Stream.empty(); } return EntryStream. of(map).filter(filter).values(); } // /** // * Lazy evaluation. // *
// * // * This is equal to: {@code Stream.just(supplier).flatmap(it -> it.get())}. // * // * @param supplier // * @return // */ // @Beta // public static Stream from(final Supplier> supplier) { // N.checkArgNotNull(supplier, "supplier"); // // return Stream.just(supplier).flatmap(Supplier::get); // } /** * Lazy evaluation. *
* * This is equal to: {@code Stream.just(supplier).flatMap(it -> it.get())}. * * @param * @param supplier * @return */ public static Stream defer(final Supplier> supplier) { N.checkArgNotNull(supplier, "supplier"); return Stream.just(supplier).flatMap(Supplier::get); } /** * * * @param startInclusive * @param endExclusive * @return */ public static Stream range(final int startInclusive, final int endExclusive) { return IntStream.range(startInclusive, endExclusive).boxed(); } /** * * * @param startInclusive * @param endExclusive * @param by * @return */ public static Stream range(final int startInclusive, final int endExclusive, final int by) { return IntStream.range(startInclusive, endExclusive, by).boxed(); } /** * * * @param startInclusive * @param endExclusive * @return */ public static Stream range(final long startInclusive, final long endExclusive) { return LongStream.range(startInclusive, endExclusive).boxed(); } /** * * * @param startInclusive * @param endExclusive * @param by * @return */ public static Stream range(final long startInclusive, final long endExclusive, final long by) { return LongStream.range(startInclusive, endExclusive, by).boxed(); } /** * * * @param startInclusive * @param endInclusive * @return */ public static Stream rangeClosed(final int startInclusive, final int endInclusive) { return IntStream.rangeClosed(startInclusive, endInclusive).boxed(); } /** * * * @param startInclusive * @param endInclusive * @param by * @return */ public static Stream rangeClosed(final int startInclusive, final int endInclusive, final int by) { return IntStream.rangeClosed(startInclusive, endInclusive, by).boxed(); } /** * * * @param startInclusive * @param endInclusive * @return */ public static Stream rangeClosed(final long startInclusive, final long endInclusive) { return LongStream.rangeClosed(startInclusive, endInclusive).boxed(); } /** * * * @param startInclusive * @param endInclusive * @param by * @return */ public static Stream rangeClosed(final long startInclusive, final long endInclusive, final long by) { return LongStream.rangeClosed(startInclusive, endInclusive, by).boxed(); } /** * * * @param str * @param delimiter * @return */ public static Stream split(final CharSequence str, final CharSequence delimiter) { return Splitter.with(delimiter).splitToStream(str); } /** * * * @param * @param c * @return */ public static Stream flatten(final Collection> c) { return of(c).flatmap(Fn.> identity()); } /** * * * @param * @param a * @return */ public static Stream flatten(final T[][] a) { return of(a).flattMap(Fn. identity()); } /** * * * @param * @param a * @param vertically * @return */ public static Stream flatten(final T[][] a, final boolean vertically) { if (N.isNullOrEmpty(a)) { return empty(); } else if (a.length == 1) { return of(a[0]); } else if (!vertically) { return of(a).flattMap(Fn. identity()); } long n = 0; for (T[] e : a) { n += N.len(e); } if (n == 0) { return empty(); } final int rows = N.len(a); final long count = n; final Iterator iter = new ObjIteratorEx<>() { private int rowNum = 0; private int colNum = 0; private long cnt = 0; @Override public boolean hasNext() { return cnt < count; } @Override public T next() { if (cnt++ >= count) { throw new NoSuchElementException(); } if (rowNum == rows) { rowNum = 0; colNum++; } while (a[rowNum] == null || colNum >= a[rowNum].length) { if (rowNum < rows - 1) { rowNum++; } else { rowNum = 0; colNum++; } } return a[rowNum++][colNum]; } }; return of(iter); } /** * * * @param * @param a * @param valueForNone * @param vertically * @return */ public static Stream flatten(final T[][] a, final T valueForNone, final boolean vertically) { if (N.isNullOrEmpty(a)) { return empty(); } else if (a.length == 1) { return of(a[0]); } long n = 0; int maxLen = 0; for (T[] e : a) { n += N.len(e); maxLen = N.max(maxLen, N.len(e)); } if (n == 0) { return empty(); } final int rows = N.len(a); final int cols = maxLen; final long count = (long) rows * cols; Iterator iter = null; if (vertically) { iter = new ObjIteratorEx<>() { private int rowNum = 0; private int colNum = 0; private long cnt = 0; @Override public boolean hasNext() { return cnt < count; } @Override public T next() { if (cnt++ >= count) { throw new NoSuchElementException(); } if (rowNum == rows) { rowNum = 0; colNum++; } if (a[rowNum] == null || colNum >= a[rowNum].length) { rowNum++; return valueForNone; } else { return a[rowNum++][colNum]; } } }; } else { iter = new ObjIteratorEx<>() { private int rowNum = 0; private int colNum = 0; private long cnt = 0; @Override public boolean hasNext() { return cnt < count; } @Override public T next() { if (cnt++ >= count) { throw new NoSuchElementException(); } if (colNum >= cols) { colNum = 0; rowNum++; } if (a[rowNum] == null || colNum >= a[rowNum].length) { colNum++; return valueForNone; } else { return a[rowNum][colNum++]; } } }; } return of(iter); } /** * * * @param * @param a * @return */ public static Stream flatten(final T[][][] a) { return of(a).flattMap(e -> e).flattMap(Fn. identity()); } /** * * * @param * @param element * @param n * @return */ public static Stream repeat(final T element, final long n) { N.checkArgNotNegative(n, "n"); if (n == 0) { return empty(); } return new IteratorStream<>(new ObjIteratorEx() { private long cnt = n; @Override public boolean hasNext() { return cnt > 0; } @Override public T next() { if (cnt-- <= 0) { throw new NoSuchElementException(); } return element; } @Override public void advance(long n) { cnt = n >= cnt ? 0 : cnt - (int) n; } @Override public long count() { return cnt; } @Override public
A[] toArray(A[] a) { a = a.length >= cnt ? a : N.copyOf(a, (int) cnt); for (int i = 0; i < cnt; i++) { a[i] = (A) element; } cnt = 0; return a; } }); } /** * * * @param * @param hasNext * @param next * @return */ public static Stream iterate(final BooleanSupplier hasNext, final Supplier next) { N.checkArgNotNull(hasNext); N.checkArgNotNull(next); return of(new ObjIteratorEx() { private boolean hasNextVal = false; @Override public boolean hasNext() { if (!hasNextVal) { hasNextVal = hasNext.getAsBoolean(); } return hasNextVal; } @Override public T next() { if (!hasNextVal && !hasNext()) { throw new NoSuchElementException(); } hasNextVal = false; return next.get(); } }); } /** * Returns a sequential ordered {@code Stream} produced by iterative * application of a function {@code f} to an initial element {@code init}, * producing a {@code Stream} consisting of {@code init}, {@code f(init)}, * {@code f(f(init))}, etc. * *

The first element (position {@code 0}) in the {@code Stream} will be * the provided {@code init}. For {@code n > 0}, the element at position * {@code n}, will be the result of applying the function {@code f} to the * element at position {@code n - 1}. * * @param * @param init * @param hasNext * @param f * @return */ public static Stream iterate(final T init, final BooleanSupplier hasNext, final UnaryOperator f) { N.checkArgNotNull(hasNext); N.checkArgNotNull(f); return of(new ObjIteratorEx() { private T t = (T) NONE; private boolean hasNextVal = false; @Override public boolean hasNext() { if (!hasNextVal) { hasNextVal = hasNext.getAsBoolean(); } return hasNextVal; } @Override public T next() { if (!hasNextVal && !hasNext()) { throw new NoSuchElementException(); } hasNextVal = false; return t = (t == NONE) ? init : f.apply(t); } }); } /** * * * @param * @param init * @param hasNext test if has next by hasNext.test(init) for first time and hasNext.test(f.apply(previous)) for remaining. * @param f * @return */ public static Stream iterate(final T init, final Predicate hasNext, final UnaryOperator f) { N.checkArgNotNull(hasNext); N.checkArgNotNull(f); return of(new ObjIteratorEx() { private T t = (T) NONE; private T cur = (T) NONE; private boolean hasMore = true; private boolean hasNextVal = false; @Override public boolean hasNext() { if (!hasNextVal && hasMore) { hasNextVal = hasNext.test((cur = (t == NONE ? init : f.apply(t)))); if (!hasNextVal) { hasMore = false; } } return hasNextVal; } @Override public T next() { if (!hasNextVal && !hasNext()) { throw new NoSuchElementException(); } t = cur; cur = (T) NONE; hasNextVal = false; return t; } }); } /** * * * @param * @param init * @param f * @return */ public static Stream iterate(final T init, final UnaryOperator f) { N.checkArgNotNull(f); return of(new ObjIteratorEx() { private T t = (T) NONE; @Override public boolean hasNext() { return true; } @Override public T next() { return t = t == NONE ? init : f.apply(t); } }); } /** * * * @param * @param supplier * @return */ public static Stream generate(final Supplier supplier) { N.checkArgNotNull(supplier, "supplier"); return of(new ObjIteratorEx() { @Override public boolean hasNext() { return true; } @Override public T next() { return supplier.get(); } }); } /** * * * @param * @param intervalInMillis * @param s * @return */ public static Stream interval(final long intervalInMillis, final Supplier s) { return interval(0, intervalInMillis, s); } /** * * * @param * @param delayInMillis * @param intervalInMillis * @param s * @return * @see java.util.concurrent.TimeUnit */ public static Stream interval(final long delayInMillis, final long intervalInMillis, final Supplier s) { return interval(delayInMillis, intervalInMillis, TimeUnit.MILLISECONDS, s); } /** * * * @param * @param delay * @param interval * @param unit * @param s * @return */ public static Stream interval(final long delay, final long interval, final TimeUnit unit, final Supplier s) { N.checkArgNotNull(s); return LongStream.interval(delay, interval, unit).mapToObj(value -> s.get()); } /** * * * @param * @param intervalInMillis * @param s * @return */ public static Stream interval(final long intervalInMillis, final LongFunction s) { return interval(0, intervalInMillis, s); } /** * * * @param * @param delayInMillis * @param intervalInMillis * @param s * @return * @see java.util.concurrent.TimeUnit */ public static Stream interval(final long delayInMillis, final long intervalInMillis, final LongFunction s) { return interval(delayInMillis, intervalInMillis, TimeUnit.MILLISECONDS, s); } /** * * * @param * @param delay * @param interval * @param unit * @param s * @return */ public static Stream interval(final long delay, final long interval, final TimeUnit unit, final LongFunction s) { N.checkArgNotNull(s); return LongStream.interval(delay, interval, unit).mapToObj(s); } /** * * * @param file * @return * @throws UncheckedIOException */ public static Stream lines(final File file) throws UncheckedIOException { return lines(file, Charsets.UTF_8); } /** * * * @param file * @param charset * @return * @throws UncheckedIOException */ public static Stream lines(final File file, final Charset charset) throws UncheckedIOException { final ObjIteratorEx iter = createLazyLineIterator(file, null, charset, null, true); return of(iter).onClose(iter::close); } /** * * * @param path * @return * @throws UncheckedIOException */ public static Stream lines(final Path path) throws UncheckedIOException { return lines(path, Charsets.UTF_8); } /** * * * @param path * @param charset * @return * @throws UncheckedIOException */ public static Stream lines(final Path path, final Charset charset) throws UncheckedIOException { final ObjIteratorEx iter = createLazyLineIterator(null, path, charset, null, true); return of(iter).onClose(iter::close); } /** * It's user's responsibility to close the input reader after the stream is finished. * * @param reader * @return * @throws UncheckedIOException */ public static Stream lines(final Reader reader) throws UncheckedIOException { N.checkArgNotNull(reader); return of(createLazyLineIterator(null, null, Charsets.UTF_8, reader, false)); } private static ObjIteratorEx createLazyLineIterator(final File file, final Path path, final Charset charset, final Reader reader, final boolean closeReader) { return ObjIteratorEx.defer(new Supplier>() { private ObjIteratorEx lazyIter = null; @Override public synchronized ObjIteratorEx get() { if (lazyIter == null) { lazyIter = new ObjIteratorEx<>() { private BufferedReader bufferedReader; { //NOSONAR 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 final LineIterator lineIterator = new LineIterator(bufferedReader); @Override public boolean hasNext() { return lineIterator.hasNext(); } @Override public String next() { return lineIterator.next(); } @Override public void close() { if (closeReader) { IOUtil.closeQuietly(bufferedReader); } } }; } return lazyIter; } }); } /** * * * @param parentPath * @return * @throws UncheckedIOException */ public static Stream listFiles(final File parentPath) throws UncheckedIOException { if (!parentPath.exists()) { return empty(); } return of(parentPath.listFiles()); } /** * * * @param parentPath * @param recursively * @return * @throws UncheckedIOException */ public static Stream listFiles(final File parentPath, final boolean recursively) throws UncheckedIOException { if (!parentPath.exists()) { return empty(); } else if (!recursively) { return of(parentPath.listFiles()); } final ObjIterator iter = new ObjIterator<>() { 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()) { throw new NoSuchElementException(); } if (subFiles[cursor].isDirectory()) { paths.offer(subFiles[cursor]); } return subFiles[cursor++]; } }; return of(iter); } /** * Sample code: * *

     * 
     * final BlockingQueue queue = new ArrayBlockingQueue<>(32);
     * N.asyncExecute(() -> Stream.observe(queue, Duration.ofMillis(100)).filter(s -> s.startsWith("a")).forEach(Fn.println()));
     * N.asList("a", "b", "ab", "bc", "1", "a").forEach(queue::add);
     * N.sleep(10);
     * N.println("==================");
     * N.sleep(100);
     * N.println("==================");
     * N.sleep(10);
     * 
     * 
* * @param * @param queue * @param duration * @return * @see com.landawn.abacus.util.Observer */ @Beta public static Stream observe(final BlockingQueue queue, final Duration duration) { N.checkArgNotNull(queue, "queue"); N.checkArgNotNull(duration, "duration"); final long now = System.currentTimeMillis(); final long endTime = duration.toMillis() >= Long.MAX_VALUE - now ? Long.MAX_VALUE : now + duration.toMillis(); final Iterator iter = new ObjIterator<>() { private T next = null; @Override public boolean hasNext() { if (next == null) { final long curTime = System.currentTimeMillis(); if (curTime <= endTime) { try { next = queue.poll(endTime - curTime, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { throw new RuntimeException(e); } } } return next != null; } @Override public T next() { if (!hasNext()) { throw new NoSuchElementException(); } final T res = next; next = null; return res; } }; return of(iter); } /** * Sample code: * *
     * 
     * final BlockingQueue queue = new ArrayBlockingQueue<>(32);
     * final MutableBoolean hasMore = MutableBoolean.of(true);
     * N.asyncExecute(() -> Stream.observe(queue, () -> hasMore.value(), 10).filter(s -> s.startsWith("a")).forEach(Fn.println()));
     * N.asList("a", "b", "ab", "bc", "1", "a").forEach(queue::add);
     * N.println("==================");
     * hasMore.setFalse();
     * N.sleep(50);
     * N.println("==================");
     * 
     * 
* * @param * @param queue * @param hasMore it will will be set to {@code true} if Stream is completed and the upstream should not continue to put elements to queue when it's completed. * This is an output parameter. * @param maxWaitIntervalInMillis * @return * @see com.landawn.abacus.util.Observer */ @Beta public static Stream observe(final BlockingQueue queue, final BooleanSupplier hasMore, final long maxWaitIntervalInMillis) { N.checkArgNotNull(queue, "queue"); N.checkArgNotNull(hasMore, "hasMore"); N.checkArgPositive(maxWaitIntervalInMillis, "maxWaitIntervalInMillis"); final Iterator iter = new ObjIterator<>() { private T next = null; @Override public boolean hasNext() { if (next == null && (hasMore.getAsBoolean() || queue.size() > 0)) { try { do { next = queue.poll(maxWaitIntervalInMillis, TimeUnit.MILLISECONDS); } while (next == null && (hasMore.getAsBoolean() || queue.size() > 0)); } catch (InterruptedException e) { throw new RuntimeException(e); } } return next != null; } @Override public T next() { if (!hasNext()) { throw new NoSuchElementException(); } final T res = next; next = null; return res; } }; return of(iter); } /** * * * @param * @param a * @return */ @SafeVarargs public static Stream concat(final T[]... a) { if (N.isNullOrEmpty(a)) { return empty(); } return of(Iterators.concat(a)); } /** * * * @param * @param a * @return */ @SafeVarargs public static Stream concat(final Iterable... a) { if (N.isNullOrEmpty(a)) { return empty(); } return of(Iterators.concat(a)); } /** * * * @param * @param a * @return */ @SafeVarargs public static Stream concat(final Iterator... a) { if (N.isNullOrEmpty(a)) { return empty(); } return of(Iterators.concat(a)); } /** * * * @param * @param a * @return */ @SafeVarargs public static Stream concat(final Stream... a) { if (N.isNullOrEmpty(a)) { return empty(); } return concat(Array.asList(a)); } /** * * * @param * @param c * @return */ public static Stream concat(final Collection> c) { if (N.isNullOrEmpty(c)) { return empty(); } return of(new ObjIteratorEx() { private final Iterator> iterators = c.iterator(); private Stream cur; private Iterator iter; @Override public boolean hasNext() { while ((iter == null || !iter.hasNext()) && iterators.hasNext()) { if (cur != null) { cur.close(); } cur = iterators.next(); iter = cur == null ? null : cur.iteratorEx(); } return iter != null && iter.hasNext(); } @Override public T next() { if ((iter == null || !iter.hasNext()) && !hasNext()) { throw new NoSuchElementException(); } return iter.next(); } }).onClose(newCloseHandler(c)); } /** * * * @param * @param c * @return */ @Beta public static Stream concatIterables(final Collection> c) { if (N.isNullOrEmpty(c)) { return empty(); } return of(new ObjIteratorEx() { private final Iterator> iterators = c.iterator(); private Iterable coll; private Iterator cur; @Override public boolean hasNext() { while ((cur == null || !cur.hasNext()) && iterators.hasNext()) { cur = (coll = iterators.next()) == null ? null : coll.iterator(); } return cur != null && cur.hasNext(); } @Override public T next() { if ((cur == null || !cur.hasNext()) && !hasNext()) { throw new NoSuchElementException(); } return cur.next(); } }); } /** * * * @param * @param c * @return */ @Beta public static Stream concatIterators(final Collection> c) { if (N.isNullOrEmpty(c)) { return empty(); } return of(new ObjIteratorEx() { private final Iterator> iterators = c.iterator(); private Iterator cur; @Override public boolean hasNext() { while ((cur == null || !cur.hasNext()) && iterators.hasNext()) { cur = iterators.next(); } return cur != null && cur.hasNext(); } @Override public T next() { if ((cur == null || !cur.hasNext()) && !hasNext()) { throw new NoSuchElementException(); } return cur.next(); } }); } /** * * * @param * @param a * @return */ @SafeVarargs public static Stream parallelConcat(final Iterable... a) { final int readTheadNum = DEFAULT_READING_THREAD_NUM; return parallelConcat(a, readTheadNum, calculateBufferedSize(a.length, readTheadNum)); } /** * * * @param * @param a * @param readThreadNum - count of threads used to read elements from iterator to queue. Default value is min(8, a.length) * @param bufferSize * @return */ public static Stream parallelConcat(final Iterable[] a, final int readThreadNum, final int bufferSize) { if (N.isNullOrEmpty(a)) { return empty(); } return parallelConcatIterables(Array.asList(a), readThreadNum, bufferSize); } /** * * * @param * @param a * @return */ @SafeVarargs public static Stream parallelConcat(final Iterator... a) { final int readTheadNum = DEFAULT_READING_THREAD_NUM; return parallelConcat(a, readTheadNum, calculateBufferedSize(a.length, readTheadNum)); } /** * * * @param * @param a * @param readThreadNum - count of threads used to read elements from iterator to queue. Default value is min(8, a.length) * @param bufferSize * @return */ public static Stream parallelConcat(final Iterator[] a, final int readThreadNum, final int bufferSize) { if (N.isNullOrEmpty(a)) { return empty(); } return parallelConcatIterators(Array.asList(a), readThreadNum, bufferSize); } /** * * * @param * @param a * @return */ @SafeVarargs public static Stream parallelConcat(final Stream... a) { final int readTheadNum = DEFAULT_READING_THREAD_NUM; return parallelConcat(a, readTheadNum, calculateBufferedSize(a.length, readTheadNum)); } /** * Returns a Stream with elements from a temporary queue which is filled by reading the elements from the specified iterators in parallel. * * @param * @param a * @param readThreadNum - count of threads used to read elements from iterator to queue. Default value is min(8, a.length) * @param bufferSize * @return */ public static Stream parallelConcat(final Stream[] a, final int readThreadNum, final int bufferSize) { if (N.isNullOrEmpty(a)) { return empty(); } return parallelConcat(Array.asList(a), readThreadNum, bufferSize); } /** * * * @param * @param c * @return */ public static Stream parallelConcat(final Collection> c) { return parallelConcat(c, DEFAULT_READING_THREAD_NUM); } /** * * * @param * @param c * @param readThreadNum * @return */ public static Stream parallelConcat(final Collection> c, final int readThreadNum) { return parallelConcat(c, readThreadNum, calculateBufferedSize(c.size(), readThreadNum)); } /** * Returns a Stream with elements from a temporary queue which is filled by reading the elements from the specified iterators in parallel. * * @param * @param c * @param readThreadNum - count of threads used to read elements from iterator to queue. Default value is min(8, c.size()) * @param bufferSize Default value is N.min(128, c.size() * 16) * @return */ public static Stream parallelConcat(final Collection> c, final int readThreadNum, final int bufferSize) { if (N.isNullOrEmpty(c)) { return Stream.empty(); } final MutableBoolean onGoing = MutableBoolean.of(true); final int threadNum = Math.min(c.size(), readThreadNum); final List> futureList = new ArrayList<>(threadNum); final Holder holderForAsyncExecutorUsed = new Holder<>(); final Supplier> supplier = () -> { final ArrayBlockingQueue queue = new ArrayBlockingQueue<>(bufferSize); final Holder eHolder = new Holder<>(); final MutableBoolean onGoing1 = MutableBoolean.of(true); final MutableBoolean disposableChecked = MutableBoolean.of(false); final Iterator> iterators = c.iterator(); final AtomicInteger threadCounter = new AtomicInteger(threadNum); boolean noException = false; AsyncExecutor asyncExecutorToUse = checkAsyncExecutor(DEFAULT_ASYNC_EXECUTOR, threadNum, 0); // TODO Warning: Dead lock could happen if the total thread number started by this stream and its upstream is bigger than StreamBase.CORE_THREAD_POOL_SIZE(1024). // If the total thread number started by this stream and its down stream is big, please specified its owner {@code Executor} by {@code parallel(..., Executor)}. // UPDATE: this dead lock problem has been resolved by using BaseStream.execute(...) try { for (int i = 0; i < threadNum; i++) { asyncExecutorToUse = execute(asyncExecutorToUse, threadNum, 0, i, futureList, new Runnable() { @SuppressWarnings({ "null", "resource" }) @Override public void run() { try { Stream s = null; Iterator iter = null; while (onGoing1.value()) { synchronized (iterators) { if (iterators.hasNext()) { s = iterators.next(); iter = s == null ? ObjIterator. empty() : iterate(s); } else { break; } } T next = null; while (onGoing1.value() && iter.hasNext()) { next = iter.next(); if (next == null) { next = (T) NONE; } else if (disposableChecked.isFalse()) { disposableChecked.setTrue(); if (next instanceof NoCachingNoUpdating) { throw new RuntimeException("Can't run NoCachingNoUpdating Objects in parallel Stream or Queue"); } } if (!queue.offer(next)) { // int cnt = 0; while (onGoing1.value()) { if (queue.offer(next, MAX_WAIT_TIME_FOR_QUEUE_OFFER, TimeUnit.MILLISECONDS)) { break; } // cnt++; // // if ((cnt % 128) == 0) { // if (logger.isWarnEnabled()) { // logger.warn("Has been waiting for " + cnt * MAX_WAIT_TIME_FOR_QUEUE_OFFER // + " milliseconds to add next element to queue. Maybe dead lock. Please refer to java doc for Stream.parallel(...) to avoid potential dead lock"); // } // } // if (MAX_WAIT_TIME_FOR_QUEUE_OFFER * cnt >= MAX_WAIT_TO_BREAK_FOR_DEAD_LOCK) { // throw new RuntimeException("Wait too long(" + MAX_WAIT_TIME_FOR_QUEUE_OFFER * cnt // + " milliseconds) to add next element to queue. Break for potential dead lock"); // } } } } if (s != null) { s.close(); } } } catch (Exception e) { setError(eHolder, e, onGoing1); } finally { threadCounter.decrementAndGet(); } } }); } noException = true; } finally { if (!noException) { onGoing1.setFalse(); } } holderForAsyncExecutorUsed.setValue(asyncExecutorToUse); return new BufferedIterator(bufferSize) { T next = null; @Override public boolean hasNext() { try { if (next == null && (next = queue.poll()) == null) { // int cnt = 0; while (onGoing1.value() && (threadCounter.get() > 0 || queue.size() > 0)) { // (queue.size() > 0 || counter.get() > 0) is wrong. has to check counter first if ((next = queue.poll(MAX_WAIT_TIME_FOR_QUEUE_POLL, TimeUnit.MILLISECONDS)) != null) { break; } // cnt++; // // if ((cnt % 128) == 0) { // if (logger.isWarnEnabled()) { // logger.warn("Has been waiting for " + cnt * MAX_WAIT_TIME_FOR_QUEUE_POLL // + " milliseconds to poll next element from queue. Maybe dead lock. Please refer to java doc for Stream.parallel(...) to avoid potential dead lock"); // } // } // if (MAX_WAIT_TIME_FOR_QUEUE_POLL * cnt >= MAX_WAIT_TO_BREAK_FOR_DEAD_LOCK) { // throw new RuntimeException("Wait too long(" + MAX_WAIT_TIME_FOR_QUEUE_POLL * cnt // + " milliseconds) to poll next element from queue. Break for potential dead lock"); // } } } } catch (Exception e) { setError(eHolder, e, onGoing1); } if (eHolder.value() != null) { setStopFlagAndThrowException(eHolder, onGoing1); } return next != null; } @Override public T next() { if (next == null && !hasNext()) { throw new NoSuchElementException(); } T result = next == NONE ? null : next; next = null; return result; } }; }; return just(supplier).flatMap(it -> Stream.of(it.get())).onClose(newCloseHandler(c)).onClose(() -> { onGoing.setFalse(); if (holderForAsyncExecutorUsed.isNotNull()) { shutdownTempExecutor(holderForAsyncExecutorUsed.value()); } // cancelAll(futureList); }); } /** * * * @param * @param c * @return */ @Beta public static Stream parallelConcatIterables(final Collection> c) { return parallelConcatIterables(c, DEFAULT_READING_THREAD_NUM); } /** * * * @param * @param c * @param readThreadNum * @return */ @Beta public static Stream parallelConcatIterables(final Collection> c, final int readThreadNum) { return parallelConcatIterables(c, readThreadNum, calculateBufferedSize(c.size(), readThreadNum)); } /** * Returns a Stream with elements from a temporary queue which is filled by reading the elements from the specified iterators in parallel. * * @param * @param c * @param readThreadNum - count of threads used to read elements from iterator to queue. Default value is min(8, c.size()) * @param bufferSize Default value is N.min(128, c.size() * 16) * @return */ @Beta public static Stream parallelConcatIterables(final Collection> c, final int readThreadNum, final int bufferSize) { if (N.isNullOrEmpty(c)) { return Stream.empty(); } return parallelConcatIterators(Stream.of(c).skipNulls().map(Iterable::iterator).toList(), readThreadNum, bufferSize); } /** * * * @param * @param c * @return */ public static Stream parallelConcatIterators(final Collection> c) { return parallelConcatIterators(c, DEFAULT_READING_THREAD_NUM); } /** * * * @param * @param c * @param readThreadNum * @return */ public static Stream parallelConcatIterators(final Collection> c, final int readThreadNum) { return parallelConcatIterators(c, readThreadNum, 0, false, null); } /** * * * @param * @param c * @param readThreadNum - count of threads used to read elements from iterator to queue. Default value is min(8, c.size()) * @param bufferSize Default value is N.min(128, c.size() * 16) * @return */ public static Stream parallelConcatIterators(final Collection> c, final int readThreadNum, final int bufferSize) { if (N.isNullOrEmpty(c)) { return Stream.empty(); } final ArrayBlockingQueue queue = new ArrayBlockingQueue<>(bufferSize); return parallelConcatIterators(c, readThreadNum, queue); } static Stream parallelConcatIterators(final Collection> c, final int readThreadNum, final ArrayBlockingQueue queue) { if (N.isNullOrEmpty(c)) { return Stream.empty(); } return Stream.parallelConcatIterators(c, readThreadNum, 0, queue, false, null); } static Stream parallelConcatIterators(final Collection> c, final int readThreadNum, final int executorNumForVirtualThread, final boolean cancelUncompletedThreads, final AsyncExecutor asyncExecutor) { return parallelConcatIterators(c, readThreadNum, executorNumForVirtualThread, calculateBufferedSize(c.size(), readThreadNum), cancelUncompletedThreads, asyncExecutor); } static Stream parallelConcatIterators(final Collection> c, final int readThreadNum, final int executorNumForVirtualThread, final int bufferSize, final boolean cancelUncompletedThreads, final AsyncExecutor asyncExecutor) { if (N.isNullOrEmpty(c)) { return Stream.empty(); } final ArrayBlockingQueue queue = new ArrayBlockingQueue<>(bufferSize); return Stream.parallelConcatIterators(c, readThreadNum, executorNumForVirtualThread, queue, cancelUncompletedThreads, asyncExecutor); } /** * * @param a * @param readThreadNum - count of threads used to read elements from iterator to queue. Default value is min(8, c.size()) * @param bufferSize Default value is N.min(128, c.size() * 16) * @param cancelUncompletedThreads * @param asyncExecutor; * @return */ static Stream parallelConcatIterators(final Collection> c, final int readThreadNum, final int executorNumForVirtualThread, final ArrayBlockingQueue queue, final boolean cancelUncompletedThreads, final AsyncExecutor asyncExecutor) { if (N.isNullOrEmpty(c)) { return Stream.empty(); } final int bufferSize = queue.remainingCapacity(); final MutableBoolean onGoing = MutableBoolean.of(true); final int threadNum = Math.min(c.size(), readThreadNum); final Holder holderForAsyncExecutorUsed = new Holder<>(); final Supplier> supplier = () -> { final Holder eHolder = new Holder<>(); final MutableBoolean disposableChecked = MutableBoolean.of(false); final List> futureList = new ArrayList<>(threadNum); final Iterator> iterators = c.iterator(); final AtomicInteger threadCounter = new AtomicInteger(threadNum); boolean noException = false; AsyncExecutor asyncExecutorToUse = checkAsyncExecutor(asyncExecutor, threadNum, executorNumForVirtualThread); // TODO Warning: Dead lock could happen if the total thread number started by this stream and its upstream is bigger than StreamBase.CORE_THREAD_POOL_SIZE(1024). // If the total thread number started by this stream and its down stream is big, please specified its owner {@code Executor} by {@code parallel(..., Executor)}. // UPDATE: this dead lock problem has been resolved by using BaseStream.execute(...) try { for (int i = 0; i < threadNum; i++) { asyncExecutorToUse = execute(asyncExecutorToUse, threadNum, executorNumForVirtualThread, i, futureList, () -> { try { while (onGoing.value()) { Iterator iter = null; synchronized (iterators) { if (iterators.hasNext()) { iter = iterators.next(); } else { break; } } T next = null; while (onGoing.value() && iter.hasNext()) { next = iter.next(); if (next == null) { next = (T) NONE; } else if (disposableChecked.isFalse()) { disposableChecked.setTrue(); if (next instanceof NoCachingNoUpdating) { throw new RuntimeException("Can't run NoCachingNoUpdating Objects in parallel Stream or Queue"); } } if (!queue.offer(next)) { // int cnt = 0; while (onGoing.value()) { if (queue.offer(next, MAX_WAIT_TIME_FOR_QUEUE_OFFER, TimeUnit.MILLISECONDS)) { break; } // cnt++; // // if ((cnt % 128) == 0) { // if (logger.isWarnEnabled()) { // logger.warn("Has been waiting for " + cnt * MAX_WAIT_TIME_FOR_QUEUE_OFFER // + " milliseconds to add next element to queue. Maybe dead lock. Please refer to java doc for Stream.parallel(...) to avoid potential dead lock"); // } // } // if (MAX_WAIT_TIME_FOR_QUEUE_OFFER * cnt >= MAX_WAIT_TO_BREAK_FOR_DEAD_LOCK) { // throw new RuntimeException("Wait too long(" + MAX_WAIT_TIME_FOR_QUEUE_OFFER * cnt // + " milliseconds) to add next element to queue. Break for potential dead lock"); // } } } } } } catch (Exception e) { setError(eHolder, e, onGoing); } finally { threadCounter.decrementAndGet(); } }); } noException = true; } finally { if (!noException) { onGoing.setFalse(); } } holderForAsyncExecutorUsed.setValue(asyncExecutorToUse); return new BufferedIterator(bufferSize) { T next = null; @Override public boolean hasNext() { try { if (next == null && (next = queue.poll()) == null) { // int cnt = 0; while (onGoing.value() && (threadCounter.get() > 0 || queue.size() > 0)) { // (queue.size() > 0 || counter.get() > 0) is wrong. has to check counter first if ((next = queue.poll(MAX_WAIT_TIME_FOR_QUEUE_POLL, TimeUnit.MILLISECONDS)) != null) { break; } // cnt++; // // if ((cnt % 128) == 0) { // if (logger.isWarnEnabled()) { // logger.warn("Has been waiting for " + cnt * MAX_WAIT_TIME_FOR_QUEUE_POLL // + " milliseconds to poll next element from queue. Maybe dead lock. Please refer to java doc for Stream.parallel(...) to avoid potential dead lock"); // } // } // if (MAX_WAIT_TIME_FOR_QUEUE_POLL * cnt >= MAX_WAIT_TO_BREAK_FOR_DEAD_LOCK) { // throw new RuntimeException("Wait too long(" + MAX_WAIT_TIME_FOR_QUEUE_POLL * cnt // + " milliseconds) to poll next element from queue. Break for potential dead lock"); // } } } } catch (Exception e) { setError(eHolder, e, onGoing); } if (eHolder.value() != null) { setStopFlagAndThrowException(eHolder, onGoing); } return next != null; } @Override public T next() { if (next == null && !hasNext()) { throw new NoSuchElementException(); } T result = next == NONE ? null : next; next = null; return result; } }; }; return just(supplier).flatMap(it -> Stream.of(it.get())).onClose(() -> { onGoing.setFalse(); try { if (cancelUncompletedThreads) { // this will always be false? // cancelAll(futureList); // TODO canceling the task will impact StreamBase.activeThreadCounter? It has been fixed now - 20220815 } } finally { if (holderForAsyncExecutorUsed.isNotNull()) { final AsyncExecutor asyncExecutorToUse = holderForAsyncExecutorUsed.value(); shutdownTempExecutor(asyncExecutorToUse, asyncExecutor); } } }); } /** * 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 * @param a * @param b * @param zipFunction * @return */ public static Stream zip(final char[] a, final char[] b, final CharBiFunction zipFunction) { return zip(CharIteratorEx.of(a), CharIteratorEx.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 * @param a * @param b * @param c * @param zipFunction * @return */ public static Stream zip(final char[] a, final char[] b, final char[] c, final CharTriFunction zipFunction) { return zip(CharIteratorEx.of(a), CharIteratorEx.of(b), CharIteratorEx.of(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 * @param a * @param b * @param zipFunction * @return */ public static Stream zip(final CharIterator a, final CharIterator b, final CharBiFunction zipFunction) { return new IteratorStream<>(new ObjIteratorEx() { private final CharIterator iterA = a == null ? CharIterator.empty() : a; private final CharIterator iterB = b == null ? CharIterator.empty() : b; @Override public boolean hasNext() { return iterA.hasNext() && iterB.hasNext(); } @Override public R next() { return zipFunction.apply(iterA.nextChar(), iterB.nextChar()); } }); } /** * 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 * @param a * @param b * @param c * @param zipFunction * @return */ public static Stream zip(final CharIterator a, final CharIterator b, final CharIterator c, final CharTriFunction zipFunction) { return new IteratorStream<>(new ObjIteratorEx() { private final CharIterator iterA = a == null ? CharIterator.empty() : a; private final CharIterator iterB = b == null ? CharIterator.empty() : b; private final CharIterator iterC = c == null ? CharIterator.empty() : c; @Override public boolean hasNext() { return iterA.hasNext() && iterB.hasNext() && iterC.hasNext(); } @Override public R next() { return zipFunction.apply(iterA.nextChar(), iterB.nextChar(), iterC.nextChar()); } }); } /** * 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 * @param a * @param b * @param zipFunction * @return */ public static Stream zip(final CharStream a, final CharStream b, final CharBiFunction zipFunction) { return ((Stream) zip(iterate(a), iterate(b), zipFunction)).onClose(newCloseHandler(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 * @param a * @param b * @param c * @param zipFunction * @return */ public static Stream zip(final CharStream a, final CharStream b, final CharStream c, final CharTriFunction zipFunction) { return ((Stream) zip(iterate(a), iterate(b), iterate(c), zipFunction)).onClose(newCloseHandler(Array.asList(a, b, c))); } /** * Zip together the iterators until one of them runs out of values. * Each array of values is combined into a single value using the supplied zipFunction function. * * @param * @param c * @param zipFunction * @return */ @SuppressWarnings("resource") public static Stream zip(final Collection c, final CharNFunction zipFunction) { if (N.isNullOrEmpty(c)) { return Stream.empty(); } final int len = c.size(); final CharIterator[] iters = new CharIterator[len]; int i = 0; for (CharStream s : c) { iters[i++] = iterate(s); } return new IteratorStream<>(new ObjIteratorEx() { @Override public boolean hasNext() { for (int i = 0; i < len; i++) { if (!iters[i].hasNext()) { return false; } } return true; } @Override public R next() { final char[] args = new char[len]; for (int i = 0; i < len; i++) { args[i] = iters[i].nextChar(); } return zipFunction.apply(args); } }).onClose(newCloseHandler(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 * @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 Stream zip(final char[] a, final char[] b, final char valueForNoneA, final char valueForNoneB, final CharBiFunction zipFunction) { return zip(CharIteratorEx.of(a), CharIteratorEx.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 * @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 Stream zip(final char[] a, final char[] b, final char[] c, final char valueForNoneA, final char valueForNoneB, final char valueForNoneC, final CharTriFunction zipFunction) { return zip(CharIteratorEx.of(a), CharIteratorEx.of(b), CharIteratorEx.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 * @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 Stream zip(final CharIterator a, final CharIterator b, final char valueForNoneA, final char valueForNoneB, final CharBiFunction zipFunction) { return new IteratorStream<>(new ObjIteratorEx() { private final CharIterator iterA = a == null ? CharIterator.empty() : a; private final CharIterator iterB = b == null ? CharIterator.empty() : b; @Override public boolean hasNext() { return iterA.hasNext() || iterB.hasNext(); } @Override public R next() { if (iterA.hasNext()) { return zipFunction.apply(iterA.nextChar(), iterB.hasNext() ? iterB.nextChar() : valueForNoneB); } else { return zipFunction.apply(valueForNoneA, iterB.nextChar()); } } }); } /** * 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 * @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 Stream zip(final CharIterator a, final CharIterator b, final CharIterator c, final char valueForNoneA, final char valueForNoneB, final char valueForNoneC, final CharTriFunction zipFunction) { return new IteratorStream<>(new ObjIteratorEx() { private final CharIterator iterA = a == null ? CharIterator.empty() : a; private final CharIterator iterB = b == null ? CharIterator.empty() : b; private final CharIterator iterC = c == null ? CharIterator.empty() : c; @Override public boolean hasNext() { return iterA.hasNext() || iterB.hasNext() || iterC.hasNext(); } @Override public R next() { if (iterA.hasNext()) { return zipFunction.apply(iterA.nextChar(), iterB.hasNext() ? iterB.nextChar() : valueForNoneB, iterC.hasNext() ? iterC.nextChar() : valueForNoneC); } else if (iterB.hasNext()) { return zipFunction.apply(valueForNoneA, iterB.nextChar(), iterC.hasNext() ? iterC.nextChar() : valueForNoneC); } else { return zipFunction.apply(valueForNoneA, valueForNoneB, iterC.nextChar()); } } }); } /** * 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 * @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 Stream zip(final CharStream a, final CharStream b, final char valueForNoneA, final char valueForNoneB, final CharBiFunction zipFunction) { return ((Stream) zip(iterate(a), iterate(b), valueForNoneA, valueForNoneB, zipFunction)).onClose(newCloseHandler(a, b)); } /** * 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 * @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 Stream zip(final CharStream a, final CharStream b, final CharStream c, final char valueForNoneA, final char valueForNoneB, final char valueForNoneC, final CharTriFunction zipFunction) { return ((Stream) zip(iterate(a), iterate(b), iterate(c), valueForNoneA, valueForNoneB, valueForNoneC, zipFunction)) .onClose(newCloseHandler(Array.asList(a, b, c))); } /** * Zip together the iterators until all of them runs out of values. * Each array of values is combined into a single value using the supplied zipFunction function. * * @param * @param c * @param valuesForNone value to fill for any iterator runs out of values. * @param zipFunction * @return */ @SuppressWarnings("resource") public static Stream zip(final Collection c, final char[] valuesForNone, final CharNFunction zipFunction) { if (N.isNullOrEmpty(c)) { return Stream.empty(); } final int len = c.size(); if (len != valuesForNone.length) { throw new IllegalArgumentException("The size of 'valuesForNone' must be same as the size of the collection of iterators"); } final CharStream[] ss = c.toArray(new CharStream[len]); final CharIterator[] iters = new CharIterator[len]; for (int i = 0; i < len; i++) { iters[i] = iterate(ss[i]); } return new IteratorStream<>(new ObjIteratorEx() { @Override public boolean hasNext() { for (int i = 0; i < len; i++) { if (iters[i] != null) { if (iters[i].hasNext()) { return true; } else if (iters[i] != null) { iters[i] = null; ss[i].close(); } } } return false; } @Override public R next() { final char[] args = new char[len]; boolean hasNext = false; for (int i = 0; i < len; i++) { if (iters[i] != null && iters[i].hasNext()) { hasNext = true; args[i] = iters[i].nextChar(); } else { args[i] = valuesForNone[i]; } } if (!hasNext) { throw new NoSuchElementException(); } return zipFunction.apply(args); } }).onClose(newCloseHandler(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 * @param a * @param b * @param zipFunction * @return */ public static Stream zip(final byte[] a, final byte[] b, final ByteBiFunction zipFunction) { return zip(ByteIteratorEx.of(a), ByteIteratorEx.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 * @param a * @param b * @param c * @param zipFunction * @return */ public static Stream zip(final byte[] a, final byte[] b, final byte[] c, final ByteTriFunction zipFunction) { return zip(ByteIteratorEx.of(a), ByteIteratorEx.of(b), ByteIteratorEx.of(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 * @param a * @param b * @param zipFunction * @return */ public static Stream zip(final ByteIterator a, final ByteIterator b, final ByteBiFunction zipFunction) { return new IteratorStream<>(new ObjIteratorEx() { private final ByteIterator iterA = a == null ? ByteIterator.empty() : a; private final ByteIterator iterB = b == null ? ByteIterator.empty() : b; @Override public boolean hasNext() { return iterA.hasNext() && iterB.hasNext(); } @Override public R next() { return zipFunction.apply(iterA.nextByte(), iterB.nextByte()); } }); } /** * 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 * @param a * @param b * @param c * @param zipFunction * @return */ public static Stream zip(final ByteIterator a, final ByteIterator b, final ByteIterator c, final ByteTriFunction zipFunction) { return new IteratorStream<>(new ObjIteratorEx() { private final ByteIterator iterA = a == null ? ByteIterator.empty() : a; private final ByteIterator iterB = b == null ? ByteIterator.empty() : b; private final ByteIterator iterC = c == null ? ByteIterator.empty() : c; @Override public boolean hasNext() { return iterA.hasNext() && iterB.hasNext() && iterC.hasNext(); } @Override public R next() { return zipFunction.apply(iterA.nextByte(), iterB.nextByte(), iterC.nextByte()); } }); } /** * 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 * @param a * @param b * @param zipFunction * @return */ public static Stream zip(final ByteStream a, final ByteStream b, final ByteBiFunction zipFunction) { return ((Stream) zip(iterate(a), iterate(b), zipFunction)).onClose(newCloseHandler(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 * @param a * @param b * @param c * @param zipFunction * @return */ public static Stream zip(final ByteStream a, final ByteStream b, final ByteStream c, final ByteTriFunction zipFunction) { return ((Stream) zip(iterate(a), iterate(b), iterate(c), zipFunction)).onClose(newCloseHandler(Array.asList(a, b, c))); } /** * Zip together the iterators until one of them runs out of values. * Each array of values is combined into a single value using the supplied zipFunction function. * * @param * @param c * @param zipFunction * @return */ @SuppressWarnings("resource") public static Stream zip(final Collection c, final ByteNFunction zipFunction) { if (N.isNullOrEmpty(c)) { return Stream.empty(); } final int len = c.size(); final ByteIterator[] iters = new ByteIterator[len]; int i = 0; for (ByteStream s : c) { iters[i++] = iterate(s); } return new IteratorStream<>(new ObjIteratorEx() { @Override public boolean hasNext() { for (int i = 0; i < len; i++) { if (!iters[i].hasNext()) { return false; } } return true; } @Override public R next() { final byte[] args = new byte[len]; for (int i = 0; i < len; i++) { args[i] = iters[i].nextByte(); } return zipFunction.apply(args); } }).onClose(newCloseHandler(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 * @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 Stream zip(final byte[] a, final byte[] b, final byte valueForNoneA, final byte valueForNoneB, final ByteBiFunction zipFunction) { return zip(ByteIteratorEx.of(a), ByteIteratorEx.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 * @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 Stream zip(final byte[] a, final byte[] b, final byte[] c, final byte valueForNoneA, final byte valueForNoneB, final byte valueForNoneC, final ByteTriFunction zipFunction) { return zip(ByteIteratorEx.of(a), ByteIteratorEx.of(b), ByteIteratorEx.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 * @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 Stream zip(final ByteIterator a, final ByteIterator b, final byte valueForNoneA, final byte valueForNoneB, final ByteBiFunction zipFunction) { return new IteratorStream<>(new ObjIteratorEx() { private final ByteIterator iterA = a == null ? ByteIterator.empty() : a; private final ByteIterator iterB = b == null ? ByteIterator.empty() : b; @Override public boolean hasNext() { return iterA.hasNext() || iterB.hasNext(); } @Override public R next() { if (iterA.hasNext()) { return zipFunction.apply(iterA.nextByte(), iterB.hasNext() ? iterB.nextByte() : valueForNoneB); } else { return zipFunction.apply(valueForNoneA, iterB.nextByte()); } } }); } /** * 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 * @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 Stream zip(final ByteIterator a, final ByteIterator b, final ByteIterator c, final byte valueForNoneA, final byte valueForNoneB, final byte valueForNoneC, final ByteTriFunction zipFunction) { return new IteratorStream<>(new ObjIteratorEx() { private final ByteIterator iterA = a == null ? ByteIterator.empty() : a; private final ByteIterator iterB = b == null ? ByteIterator.empty() : b; private final ByteIterator iterC = c == null ? ByteIterator.empty() : c; @Override public boolean hasNext() { return iterA.hasNext() || iterB.hasNext() || iterC.hasNext(); } @Override public R next() { if (iterA.hasNext()) { return zipFunction.apply(iterA.nextByte(), iterB.hasNext() ? iterB.nextByte() : valueForNoneB, iterC.hasNext() ? iterC.nextByte() : valueForNoneC); } else if (iterB.hasNext()) { return zipFunction.apply(valueForNoneA, iterB.nextByte(), iterC.hasNext() ? iterC.nextByte() : valueForNoneC); } else { return zipFunction.apply(valueForNoneA, valueForNoneB, iterC.nextByte()); } } }); } /** * 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 * @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 Stream zip(final ByteStream a, final ByteStream b, final byte valueForNoneA, final byte valueForNoneB, final ByteBiFunction zipFunction) { return ((Stream) zip(iterate(a), iterate(b), valueForNoneA, valueForNoneB, zipFunction)).onClose(newCloseHandler(a, b)); } /** * 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 * @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 Stream zip(final ByteStream a, final ByteStream b, final ByteStream c, final byte valueForNoneA, final byte valueForNoneB, final byte valueForNoneC, final ByteTriFunction zipFunction) { return ((Stream) zip(iterate(a), iterate(b), iterate(c), valueForNoneA, valueForNoneB, valueForNoneC, zipFunction)) .onClose(newCloseHandler(Array.asList(a, b, c))); } /** * Zip together the iterators until all of them runs out of values. * Each array of values is combined into a single value using the supplied zipFunction function. * * @param * @param c * @param valuesForNone value to fill for any iterator runs out of values. * @param zipFunction * @return */ @SuppressWarnings("resource") public static Stream zip(final Collection c, final byte[] valuesForNone, final ByteNFunction zipFunction) { if (N.isNullOrEmpty(c)) { return Stream.empty(); } final int len = c.size(); if (len != valuesForNone.length) { throw new IllegalArgumentException("The size of 'valuesForNone' must be same as the size of the collection of iterators"); } final ByteStream[] ss = c.toArray(new ByteStream[len]); final ByteIterator[] iters = new ByteIterator[len]; for (int i = 0; i < len; i++) { iters[i] = iterate(ss[i]); } return new IteratorStream<>(new ObjIteratorEx() { @Override public boolean hasNext() { for (int i = 0; i < len; i++) { if (iters[i] != null) { if (iters[i].hasNext()) { return true; } else if (iters[i] != null) { iters[i] = null; ss[i].close(); } } } return false; } @Override public R next() { final byte[] args = new byte[len]; boolean hasNext = false; for (int i = 0; i < len; i++) { if (iters[i] != null && iters[i].hasNext()) { hasNext = true; args[i] = iters[i].nextByte(); } else { args[i] = valuesForNone[i]; } } if (!hasNext) { throw new NoSuchElementException(); } return zipFunction.apply(args); } }).onClose(newCloseHandler(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 * @param a * @param b * @param zipFunction * @return */ public static Stream zip(final short[] a, final short[] b, final ShortBiFunction zipFunction) { return zip(ShortIteratorEx.of(a), ShortIteratorEx.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 * @param a * @param b * @param c * @param zipFunction * @return */ public static Stream zip(final short[] a, final short[] b, final short[] c, final ShortTriFunction zipFunction) { return zip(ShortIteratorEx.of(a), ShortIteratorEx.of(b), ShortIteratorEx.of(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 * @param a * @param b * @param zipFunction * @return */ public static Stream zip(final ShortIterator a, final ShortIterator b, final ShortBiFunction zipFunction) { return new IteratorStream<>(new ObjIteratorEx() { private final ShortIterator iterA = a == null ? ShortIterator.empty() : a; private final ShortIterator iterB = b == null ? ShortIterator.empty() : b; @Override public boolean hasNext() { return iterA.hasNext() && iterB.hasNext(); } @Override public R next() { return zipFunction.apply(iterA.nextShort(), iterB.nextShort()); } }); } /** * 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 * @param a * @param b * @param c * @param zipFunction * @return */ public static Stream zip(final ShortIterator a, final ShortIterator b, final ShortIterator c, final ShortTriFunction zipFunction) { return new IteratorStream<>(new ObjIteratorEx() { private final ShortIterator iterA = a == null ? ShortIterator.empty() : a; private final ShortIterator iterB = b == null ? ShortIterator.empty() : b; private final ShortIterator iterC = c == null ? ShortIterator.empty() : c; @Override public boolean hasNext() { return iterA.hasNext() && iterB.hasNext() && iterC.hasNext(); } @Override public R next() { return zipFunction.apply(iterA.nextShort(), iterB.nextShort(), iterC.nextShort()); } }); } /** * 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 * @param a * @param b * @param zipFunction * @return */ public static Stream zip(final ShortStream a, final ShortStream b, final ShortBiFunction zipFunction) { return ((Stream) zip(iterate(a), iterate(b), zipFunction)).onClose(newCloseHandler(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 * @param a * @param b * @param c * @param zipFunction * @return */ public static Stream zip(final ShortStream a, final ShortStream b, final ShortStream c, final ShortTriFunction zipFunction) { return ((Stream) zip(iterate(a), iterate(b), iterate(c), zipFunction)).onClose(newCloseHandler(Array.asList(a, b, c))); } /** * Zip together the iterators until one of them runs out of values. * Each array of values is combined into a single value using the supplied zipFunction function. * * @param * @param c * @param zipFunction * @return */ @SuppressWarnings("resource") public static Stream zip(final Collection c, final ShortNFunction zipFunction) { if (N.isNullOrEmpty(c)) { return Stream.empty(); } final int len = c.size(); final ShortIterator[] iters = new ShortIterator[len]; int i = 0; for (ShortStream s : c) { iters[i++] = iterate(s); } return new IteratorStream<>(new ObjIteratorEx() { @Override public boolean hasNext() { for (int i = 0; i < len; i++) { if (!iters[i].hasNext()) { return false; } } return true; } @Override public R next() { final short[] args = new short[len]; for (int i = 0; i < len; i++) { args[i] = iters[i].nextShort(); } return zipFunction.apply(args); } }).onClose(newCloseHandler(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 * @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 Stream zip(final short[] a, final short[] b, final short valueForNoneA, final short valueForNoneB, final ShortBiFunction zipFunction) { return zip(ShortIteratorEx.of(a), ShortIteratorEx.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 * @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 Stream zip(final short[] a, final short[] b, final short[] c, final short valueForNoneA, final short valueForNoneB, final short valueForNoneC, final ShortTriFunction zipFunction) { return zip(ShortIteratorEx.of(a), ShortIteratorEx.of(b), ShortIteratorEx.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 * @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 Stream zip(final ShortIterator a, final ShortIterator b, final short valueForNoneA, final short valueForNoneB, final ShortBiFunction zipFunction) { return new IteratorStream<>(new ObjIteratorEx() { private final ShortIterator iterA = a == null ? ShortIterator.empty() : a; private final ShortIterator iterB = b == null ? ShortIterator.empty() : b; @Override public boolean hasNext() { return iterA.hasNext() || iterB.hasNext(); } @Override public R next() { if (iterA.hasNext()) { return zipFunction.apply(iterA.nextShort(), iterB.hasNext() ? iterB.nextShort() : valueForNoneB); } else { return zipFunction.apply(valueForNoneA, iterB.nextShort()); } } }); } /** * 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 * @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 Stream zip(final ShortIterator a, final ShortIterator b, final ShortIterator c, final short valueForNoneA, final short valueForNoneB, final short valueForNoneC, final ShortTriFunction zipFunction) { return new IteratorStream<>(new ObjIteratorEx() { private final ShortIterator iterA = a == null ? ShortIterator.empty() : a; private final ShortIterator iterB = b == null ? ShortIterator.empty() : b; private final ShortIterator iterC = c == null ? ShortIterator.empty() : c; @Override public boolean hasNext() { return iterA.hasNext() || iterB.hasNext() || iterC.hasNext(); } @Override public R next() { if (iterA.hasNext()) { return zipFunction.apply(iterA.nextShort(), iterB.hasNext() ? iterB.nextShort() : valueForNoneB, iterC.hasNext() ? iterC.nextShort() : valueForNoneC); } else if (iterB.hasNext()) { return zipFunction.apply(valueForNoneA, iterB.nextShort(), iterC.hasNext() ? iterC.nextShort() : valueForNoneC); } else { return zipFunction.apply(valueForNoneA, valueForNoneB, iterC.nextShort()); } } }); } /** * 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 * @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 Stream zip(final ShortStream a, final ShortStream b, final short valueForNoneA, final short valueForNoneB, final ShortBiFunction zipFunction) { return ((Stream) zip(iterate(a), iterate(b), valueForNoneA, valueForNoneB, zipFunction)).onClose(newCloseHandler(a, b)); } /** * 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 * @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 Stream zip(final ShortStream a, final ShortStream b, final ShortStream c, final short valueForNoneA, final short valueForNoneB, final short valueForNoneC, final ShortTriFunction zipFunction) { return ((Stream) zip(iterate(a), iterate(b), iterate(c), valueForNoneA, valueForNoneB, valueForNoneC, zipFunction)) .onClose(newCloseHandler(Array.asList(a, b, c))); } /** * Zip together the iterators until all of them runs out of values. * Each array of values is combined into a single value using the supplied zipFunction function. * * @param * @param c * @param valuesForNone value to fill for any iterator runs out of values. * @param zipFunction * @return */ @SuppressWarnings("resource") public static Stream zip(final Collection c, final short[] valuesForNone, final ShortNFunction zipFunction) { if (N.isNullOrEmpty(c)) { return Stream.empty(); } final int len = c.size(); if (len != valuesForNone.length) { throw new IllegalArgumentException("The size of 'valuesForNone' must be same as the size of the collection of iterators"); } final ShortStream[] ss = c.toArray(new ShortStream[len]); final ShortIterator[] iters = new ShortIterator[len]; for (int i = 0; i < len; i++) { iters[i] = iterate(ss[i]); } return new IteratorStream<>(new ObjIteratorEx() { @Override public boolean hasNext() { for (int i = 0; i < len; i++) { if (iters[i] != null) { if (iters[i].hasNext()) { return true; } else if (iters[i] != null) { iters[i] = null; ss[i].close(); } } } return false; } @Override public R next() { final short[] args = new short[len]; boolean hasNext = false; for (int i = 0; i < len; i++) { if (iters[i] != null && iters[i].hasNext()) { hasNext = true; args[i] = iters[i].nextShort(); } else { args[i] = valuesForNone[i]; } } if (!hasNext) { throw new NoSuchElementException(); } return zipFunction.apply(args); } }).onClose(newCloseHandler(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 * @param a * @param b * @param zipFunction * @return */ public static Stream zip(final int[] a, final int[] b, final IntBiFunction zipFunction) { return zip(IntIteratorEx.of(a), IntIteratorEx.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 * @param a * @param b * @param c * @param zipFunction * @return */ public static Stream zip(final int[] a, final int[] b, final int[] c, final IntTriFunction zipFunction) { return zip(IntIteratorEx.of(a), IntIteratorEx.of(b), IntIteratorEx.of(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 * @param a * @param b * @param zipFunction * @return */ public static Stream zip(final IntIterator a, final IntIterator b, final IntBiFunction zipFunction) { return new IteratorStream<>(new ObjIteratorEx() { private final IntIterator iterA = a == null ? IntIterator.empty() : a; private final IntIterator iterB = b == null ? IntIterator.empty() : b; @Override public boolean hasNext() { return iterA.hasNext() && iterB.hasNext(); } @Override public R next() { return zipFunction.apply(iterA.nextInt(), iterB.nextInt()); } }); } /** * 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 * @param a * @param b * @param c * @param zipFunction * @return */ public static Stream zip(final IntIterator a, final IntIterator b, final IntIterator c, final IntTriFunction zipFunction) { return new IteratorStream<>(new ObjIteratorEx() { private final IntIterator iterA = a == null ? IntIterator.empty() : a; private final IntIterator iterB = b == null ? IntIterator.empty() : b; private final IntIterator iterC = c == null ? IntIterator.empty() : c; @Override public boolean hasNext() { return iterA.hasNext() && iterB.hasNext() && iterC.hasNext(); } @Override public R next() { return zipFunction.apply(iterA.nextInt(), iterB.nextInt(), iterC.nextInt()); } }); } /** * 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 * @param a * @param b * @param zipFunction * @return */ public static Stream zip(final IntStream a, final IntStream b, final IntBiFunction zipFunction) { return ((Stream) zip(iterate(a), iterate(b), zipFunction)).onClose(newCloseHandler(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 * @param a * @param b * @param c * @param zipFunction * @return */ public static Stream zip(final IntStream a, final IntStream b, final IntStream c, final IntTriFunction zipFunction) { return ((Stream) zip(iterate(a), iterate(b), iterate(c), zipFunction)).onClose(newCloseHandler(Array.asList(a, b, c))); } /** * Zip together the iterators until one of them runs out of values. * Each array of values is combined into a single value using the supplied zipFunction function. * * @param * @param c * @param zipFunction * @return */ @SuppressWarnings("resource") public static Stream zip(final Collection c, final IntNFunction zipFunction) { if (N.isNullOrEmpty(c)) { return Stream.empty(); } final int len = c.size(); final IntIterator[] iters = new IntIterator[len]; int i = 0; for (IntStream s : c) { iters[i++] = iterate(s); } return new IteratorStream<>(new ObjIteratorEx() { @Override public boolean hasNext() { for (int i = 0; i < len; i++) { if (!iters[i].hasNext()) { return false; } } return true; } @Override public R next() { final int[] args = new int[len]; for (int i = 0; i < len; i++) { args[i] = iters[i].nextInt(); } return zipFunction.apply(args); } }).onClose(newCloseHandler(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 * @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 Stream zip(final int[] a, final int[] b, final int valueForNoneA, final int valueForNoneB, final IntBiFunction zipFunction) { return zip(IntIteratorEx.of(a), IntIteratorEx.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 * @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 Stream zip(final int[] a, final int[] b, final int[] c, final int valueForNoneA, final int valueForNoneB, final int valueForNoneC, final IntTriFunction zipFunction) { return zip(IntIteratorEx.of(a), IntIteratorEx.of(b), IntIteratorEx.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 * @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 Stream zip(final IntIterator a, final IntIterator b, final int valueForNoneA, final int valueForNoneB, final IntBiFunction zipFunction) { return new IteratorStream<>(new ObjIteratorEx() { private final IntIterator iterA = a == null ? IntIterator.empty() : a; private final IntIterator iterB = b == null ? IntIterator.empty() : b; @Override public boolean hasNext() { return iterA.hasNext() || iterB.hasNext(); } @Override public R next() { if (iterA.hasNext()) { return zipFunction.apply(iterA.nextInt(), iterB.hasNext() ? iterB.nextInt() : valueForNoneB); } else { return zipFunction.apply(valueForNoneA, iterB.nextInt()); } } }); } /** * 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 * @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 Stream zip(final IntIterator a, final IntIterator b, final IntIterator c, final int valueForNoneA, final int valueForNoneB, final int valueForNoneC, final IntTriFunction zipFunction) { return new IteratorStream<>(new ObjIteratorEx() { private final IntIterator iterA = a == null ? IntIterator.empty() : a; private final IntIterator iterB = b == null ? IntIterator.empty() : b; private final IntIterator iterC = c == null ? IntIterator.empty() : c; @Override public boolean hasNext() { return iterA.hasNext() || iterB.hasNext() || iterC.hasNext(); } @Override public R next() { if (iterA.hasNext()) { return zipFunction.apply(iterA.nextInt(), iterB.hasNext() ? iterB.nextInt() : valueForNoneB, iterC.hasNext() ? iterC.nextInt() : valueForNoneC); } else if (iterB.hasNext()) { return zipFunction.apply(valueForNoneA, iterB.nextInt(), iterC.hasNext() ? iterC.nextInt() : valueForNoneC); } else { return zipFunction.apply(valueForNoneA, valueForNoneB, iterC.nextInt()); } } }); } /** * 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 * @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 Stream zip(final IntStream a, final IntStream b, final int valueForNoneA, final int valueForNoneB, final IntBiFunction zipFunction) { return ((Stream) zip(iterate(a), iterate(b), valueForNoneA, valueForNoneB, zipFunction)).onClose(newCloseHandler(a, b)); } /** * 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 * @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 Stream zip(final IntStream a, final IntStream b, final IntStream c, final int valueForNoneA, final int valueForNoneB, final int valueForNoneC, final IntTriFunction zipFunction) { return ((Stream) zip(iterate(a), iterate(b), iterate(c), valueForNoneA, valueForNoneB, valueForNoneC, zipFunction)) .onClose(newCloseHandler(Array.asList(a, b, c))); } /** * Zip together the iterators until all of them runs out of values. * Each array of values is combined into a single value using the supplied zipFunction function. * * @param * @param c * @param valuesForNone value to fill for any iterator runs out of values. * @param zipFunction * @return */ @SuppressWarnings("resource") public static Stream zip(final Collection c, final int[] valuesForNone, final IntNFunction zipFunction) { if (N.isNullOrEmpty(c)) { return Stream.empty(); } final int len = c.size(); if (len != valuesForNone.length) { throw new IllegalArgumentException("The size of 'valuesForNone' must be same as the size of the collection of iterators"); } final IntStream[] ss = c.toArray(new IntStream[len]); final IntIterator[] iters = new IntIterator[len]; for (int i = 0; i < len; i++) { iters[i] = iterate(ss[i]); } return new IteratorStream<>(new ObjIteratorEx() { @Override public boolean hasNext() { for (int i = 0; i < len; i++) { if (iters[i] != null) { if (iters[i].hasNext()) { return true; } else if (iters[i] != null) { iters[i] = null; ss[i].close(); } } } return false; } @Override public R next() { final int[] args = new int[len]; boolean hasNext = false; for (int i = 0; i < len; i++) { if (iters[i] != null && iters[i].hasNext()) { hasNext = true; args[i] = iters[i].nextInt(); } else { args[i] = valuesForNone[i]; } } if (!hasNext) { throw new NoSuchElementException(); } return zipFunction.apply(args); } }).onClose(newCloseHandler(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 * @param a * @param b * @param zipFunction * @return */ public static Stream zip(final long[] a, final long[] b, final LongBiFunction zipFunction) { return zip(LongIteratorEx.of(a), LongIteratorEx.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 * @param a * @param b * @param c * @param zipFunction * @return */ public static Stream zip(final long[] a, final long[] b, final long[] c, final LongTriFunction zipFunction) { return zip(LongIteratorEx.of(a), LongIteratorEx.of(b), LongIteratorEx.of(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 * @param a * @param b * @param zipFunction * @return */ public static Stream zip(final LongIterator a, final LongIterator b, final LongBiFunction zipFunction) { return new IteratorStream<>(new ObjIteratorEx() { private final LongIterator iterA = a == null ? LongIterator.empty() : a; private final LongIterator iterB = b == null ? LongIterator.empty() : b; @Override public boolean hasNext() { return iterA.hasNext() && iterB.hasNext(); } @Override public R next() { return zipFunction.apply(iterA.nextLong(), iterB.nextLong()); } }); } /** * 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 * @param a * @param b * @param c * @param zipFunction * @return */ public static Stream zip(final LongIterator a, final LongIterator b, final LongIterator c, final LongTriFunction zipFunction) { return new IteratorStream<>(new ObjIteratorEx() { private final LongIterator iterA = a == null ? LongIterator.empty() : a; private final LongIterator iterB = b == null ? LongIterator.empty() : b; private final LongIterator iterC = c == null ? LongIterator.empty() : c; @Override public boolean hasNext() { return iterA.hasNext() && iterB.hasNext() && iterC.hasNext(); } @Override public R next() { return zipFunction.apply(iterA.nextLong(), iterB.nextLong(), iterC.nextLong()); } }); } /** * 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 * @param a * @param b * @param zipFunction * @return */ public static Stream zip(final LongStream a, final LongStream b, final LongBiFunction zipFunction) { return ((Stream) zip(iterate(a), iterate(b), zipFunction)).onClose(newCloseHandler(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 * @param a * @param b * @param c * @param zipFunction * @return */ public static Stream zip(final LongStream a, final LongStream b, final LongStream c, final LongTriFunction zipFunction) { return ((Stream) zip(iterate(a), iterate(b), iterate(c), zipFunction)).onClose(newCloseHandler(Array.asList(a, b, c))); } /** * Zip together the iterators until one of them runs out of values. * Each array of values is combined into a single value using the supplied zipFunction function. * * @param * @param c * @param zipFunction * @return */ @SuppressWarnings("resource") public static Stream zip(final Collection c, final LongNFunction zipFunction) { if (N.isNullOrEmpty(c)) { return Stream.empty(); } final int len = c.size(); final LongIterator[] iters = new LongIterator[len]; int i = 0; for (LongStream s : c) { iters[i++] = iterate(s); } return new IteratorStream<>(new ObjIteratorEx() { @Override public boolean hasNext() { for (int i = 0; i < len; i++) { if (!iters[i].hasNext()) { return false; } } return true; } @Override public R next() { final long[] args = new long[len]; for (int i = 0; i < len; i++) { args[i] = iters[i].nextLong(); } return zipFunction.apply(args); } }).onClose(newCloseHandler(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 * @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 Stream zip(final long[] a, final long[] b, final long valueForNoneA, final long valueForNoneB, final LongBiFunction zipFunction) { return zip(LongIteratorEx.of(a), LongIteratorEx.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 * @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 Stream zip(final long[] a, final long[] b, final long[] c, final long valueForNoneA, final long valueForNoneB, final long valueForNoneC, final LongTriFunction zipFunction) { return zip(LongIteratorEx.of(a), LongIteratorEx.of(b), LongIteratorEx.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 * @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 Stream zip(final LongIterator a, final LongIterator b, final long valueForNoneA, final long valueForNoneB, final LongBiFunction zipFunction) { return new IteratorStream<>(new ObjIteratorEx() { private final LongIterator iterA = a == null ? LongIterator.empty() : a; private final LongIterator iterB = b == null ? LongIterator.empty() : b; @Override public boolean hasNext() { return iterA.hasNext() || iterB.hasNext(); } @Override public R next() { if (iterA.hasNext()) { return zipFunction.apply(iterA.nextLong(), iterB.hasNext() ? iterB.nextLong() : valueForNoneB); } else { return zipFunction.apply(valueForNoneA, iterB.nextLong()); } } }); } /** * 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 * @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 Stream zip(final LongIterator a, final LongIterator b, final LongIterator c, final long valueForNoneA, final long valueForNoneB, final long valueForNoneC, final LongTriFunction zipFunction) { return new IteratorStream<>(new ObjIteratorEx() { private final LongIterator iterA = a == null ? LongIterator.empty() : a; private final LongIterator iterB = b == null ? LongIterator.empty() : b; private final LongIterator iterC = c == null ? LongIterator.empty() : c; @Override public boolean hasNext() { return iterA.hasNext() || iterB.hasNext() || iterC.hasNext(); } @Override public R next() { if (iterA.hasNext()) { return zipFunction.apply(iterA.nextLong(), iterB.hasNext() ? iterB.nextLong() : valueForNoneB, iterC.hasNext() ? iterC.nextLong() : valueForNoneC); } else if (iterB.hasNext()) { return zipFunction.apply(valueForNoneA, iterB.nextLong(), iterC.hasNext() ? iterC.nextLong() : valueForNoneC); } else { return zipFunction.apply(valueForNoneA, valueForNoneB, iterC.nextLong()); } } }); } /** * 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 * @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 Stream zip(final LongStream a, final LongStream b, final long valueForNoneA, final long valueForNoneB, final LongBiFunction zipFunction) { return ((Stream) zip(iterate(a), iterate(b), valueForNoneA, valueForNoneB, zipFunction)).onClose(newCloseHandler(a, b)); } /** * 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 * @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 Stream zip(final LongStream a, final LongStream b, final LongStream c, final long valueForNoneA, final long valueForNoneB, final long valueForNoneC, final LongTriFunction zipFunction) { return ((Stream) zip(iterate(a), iterate(b), iterate(c), valueForNoneA, valueForNoneB, valueForNoneC, zipFunction)) .onClose(newCloseHandler(Array.asList(a, b, c))); } /** * Zip together the iterators until all of them runs out of values. * Each array of values is combined into a single value using the supplied zipFunction function. * * @param * @param c * @param valuesForNone value to fill for any iterator runs out of values. * @param zipFunction * @return */ @SuppressWarnings("resource") public static Stream zip(final Collection c, final long[] valuesForNone, final LongNFunction zipFunction) { if (N.isNullOrEmpty(c)) { return Stream.empty(); } final int len = c.size(); if (len != valuesForNone.length) { throw new IllegalArgumentException("The size of 'valuesForNone' must be same as the size of the collection of iterators"); } final LongStream[] ss = c.toArray(new LongStream[len]); final LongIterator[] iters = new LongIterator[len]; for (int i = 0; i < len; i++) { iters[i] = iterate(ss[i]); } return new IteratorStream<>(new ObjIteratorEx() { @Override public boolean hasNext() { for (int i = 0; i < len; i++) { if (iters[i] != null) { if (iters[i].hasNext()) { return true; } else if (iters[i] != null) { iters[i] = null; ss[i].close(); } } } return false; } @Override public R next() { final long[] args = new long[len]; boolean hasNext = false; for (int i = 0; i < len; i++) { if (iters[i] != null && iters[i].hasNext()) { hasNext = true; args[i] = iters[i].nextLong(); } else { args[i] = valuesForNone[i]; } } if (!hasNext) { throw new NoSuchElementException(); } return zipFunction.apply(args); } }).onClose(newCloseHandler(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 * @param a * @param b * @param zipFunction * @return */ public static Stream zip(final float[] a, final float[] b, final FloatBiFunction zipFunction) { return zip(FloatIteratorEx.of(a), FloatIteratorEx.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 * @param a * @param b * @param c * @param zipFunction * @return */ public static Stream zip(final float[] a, final float[] b, final float[] c, final FloatTriFunction zipFunction) { return zip(FloatIteratorEx.of(a), FloatIteratorEx.of(b), FloatIteratorEx.of(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 * @param a * @param b * @param zipFunction * @return */ public static Stream zip(final FloatIterator a, final FloatIterator b, final FloatBiFunction zipFunction) { return new IteratorStream<>(new ObjIteratorEx() { private final FloatIterator iterA = a == null ? FloatIterator.empty() : a; private final FloatIterator iterB = b == null ? FloatIterator.empty() : b; @Override public boolean hasNext() { return iterA.hasNext() && iterB.hasNext(); } @Override public R next() { return zipFunction.apply(iterA.nextFloat(), iterB.nextFloat()); } }); } /** * 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 * @param a * @param b * @param c * @param zipFunction * @return */ public static Stream zip(final FloatIterator a, final FloatIterator b, final FloatIterator c, final FloatTriFunction zipFunction) { return new IteratorStream<>(new ObjIteratorEx() { private final FloatIterator iterA = a == null ? FloatIterator.empty() : a; private final FloatIterator iterB = b == null ? FloatIterator.empty() : b; private final FloatIterator iterC = c == null ? FloatIterator.empty() : c; @Override public boolean hasNext() { return iterA.hasNext() && iterB.hasNext() && iterC.hasNext(); } @Override public R next() { return zipFunction.apply(iterA.nextFloat(), iterB.nextFloat(), iterC.nextFloat()); } }); } /** * 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 * @param a * @param b * @param zipFunction * @return */ public static Stream zip(final FloatStream a, final FloatStream b, final FloatBiFunction zipFunction) { return ((Stream) zip(iterate(a), iterate(b), zipFunction)).onClose(newCloseHandler(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 * @param a * @param b * @param c * @param zipFunction * @return */ public static Stream zip(final FloatStream a, final FloatStream b, final FloatStream c, final FloatTriFunction zipFunction) { return ((Stream) zip(iterate(a), iterate(b), iterate(c), zipFunction)).onClose(newCloseHandler(Array.asList(a, b, c))); } /** * Zip together the iterators until one of them runs out of values. * Each array of values is combined into a single value using the supplied zipFunction function. * * @param * @param c * @param zipFunction * @return */ @SuppressWarnings("resource") public static Stream zip(final Collection c, final FloatNFunction zipFunction) { if (N.isNullOrEmpty(c)) { return Stream.empty(); } final int len = c.size(); final FloatIterator[] iters = new FloatIterator[len]; int i = 0; for (FloatStream s : c) { iters[i++] = iterate(s); } return new IteratorStream<>(new ObjIteratorEx() { @Override public boolean hasNext() { for (int i = 0; i < len; i++) { if (!iters[i].hasNext()) { return false; } } return true; } @Override public R next() { final float[] args = new float[len]; for (int i = 0; i < len; i++) { args[i] = iters[i].nextFloat(); } return zipFunction.apply(args); } }).onClose(newCloseHandler(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 * @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 Stream zip(final float[] a, final float[] b, final float valueForNoneA, final float valueForNoneB, final FloatBiFunction zipFunction) { return zip(FloatIteratorEx.of(a), FloatIteratorEx.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 * @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 Stream zip(final float[] a, final float[] b, final float[] c, final float valueForNoneA, final float valueForNoneB, final float valueForNoneC, final FloatTriFunction zipFunction) { return zip(FloatIteratorEx.of(a), FloatIteratorEx.of(b), FloatIteratorEx.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 * @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 Stream zip(final FloatIterator a, final FloatIterator b, final float valueForNoneA, final float valueForNoneB, final FloatBiFunction zipFunction) { return new IteratorStream<>(new ObjIteratorEx() { private final FloatIterator iterA = a == null ? FloatIterator.empty() : a; private final FloatIterator iterB = b == null ? FloatIterator.empty() : b; @Override public boolean hasNext() { return iterA.hasNext() || iterB.hasNext(); } @Override public R next() { if (iterA.hasNext()) { return zipFunction.apply(iterA.nextFloat(), iterB.hasNext() ? iterB.nextFloat() : valueForNoneB); } else { return zipFunction.apply(valueForNoneA, iterB.nextFloat()); } } }); } /** * 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 * @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 Stream zip(final FloatIterator a, final FloatIterator b, final FloatIterator c, final float valueForNoneA, final float valueForNoneB, final float valueForNoneC, final FloatTriFunction zipFunction) { return new IteratorStream<>(new ObjIteratorEx() { private final FloatIterator iterA = a == null ? FloatIterator.empty() : a; private final FloatIterator iterB = b == null ? FloatIterator.empty() : b; private final FloatIterator iterC = c == null ? FloatIterator.empty() : c; @Override public boolean hasNext() { return iterA.hasNext() || iterB.hasNext() || iterC.hasNext(); } @Override public R next() { if (!hasNext()) { throw new NoSuchElementException(); } return zipFunction.apply(iterA.hasNext() ? iterA.nextFloat() : valueForNoneA, iterB.hasNext() ? iterB.nextFloat() : valueForNoneB, iterC.hasNext() ? iterC.nextFloat() : valueForNoneC); } }); } /** * 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 * @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 Stream zip(final FloatStream a, final FloatStream b, final float valueForNoneA, final float valueForNoneB, final FloatBiFunction zipFunction) { return ((Stream) zip(iterate(a), iterate(b), valueForNoneA, valueForNoneB, zipFunction)).onClose(newCloseHandler(a, b)); } /** * 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 * @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 Stream zip(final FloatStream a, final FloatStream b, final FloatStream c, final float valueForNoneA, final float valueForNoneB, final float valueForNoneC, final FloatTriFunction zipFunction) { return ((Stream) zip(iterate(a), iterate(b), iterate(c), valueForNoneA, valueForNoneB, valueForNoneC, zipFunction)) .onClose(newCloseHandler(Array.asList(a, b, c))); } /** * Zip together the iterators until all of them runs out of values. * Each array of values is combined into a single value using the supplied zipFunction function. * * @param * @param c * @param valuesForNone value to fill for any iterator runs out of values. * @param zipFunction * @return */ @SuppressWarnings("resource") public static Stream zip(final Collection c, final float[] valuesForNone, final FloatNFunction zipFunction) { if (N.isNullOrEmpty(c)) { return Stream.empty(); } final int len = c.size(); if (len != valuesForNone.length) { throw new IllegalArgumentException("The size of 'valuesForNone' must be same as the size of the collection of iterators"); } final FloatStream[] ss = c.toArray(new FloatStream[len]); final FloatIterator[] iters = new FloatIterator[len]; for (int i = 0; i < len; i++) { iters[i] = iterate(ss[i]); } return new IteratorStream<>(new ObjIteratorEx() { @Override public boolean hasNext() { for (int i = 0; i < len; i++) { if (iters[i] != null) { if (iters[i].hasNext()) { return true; } else if (iters[i] != null) { iters[i] = null; ss[i].close(); } } } return false; } @Override public R next() { final float[] args = new float[len]; boolean hasNext = false; for (int i = 0; i < len; i++) { if (iters[i] != null && iters[i].hasNext()) { hasNext = true; args[i] = iters[i].nextFloat(); } else { args[i] = valuesForNone[i]; } } if (!hasNext) { throw new NoSuchElementException(); } return zipFunction.apply(args); } }).onClose(newCloseHandler(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 * @param a * @param b * @param zipFunction * @return */ public static Stream zip(final double[] a, final double[] b, final DoubleBiFunction zipFunction) { return zip(DoubleIteratorEx.of(a), DoubleIteratorEx.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 * @param a * @param b * @param c * @param zipFunction * @return */ public static Stream zip(final double[] a, final double[] b, final double[] c, final DoubleTriFunction zipFunction) { return zip(DoubleIteratorEx.of(a), DoubleIteratorEx.of(b), DoubleIteratorEx.of(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 * @param a * @param b * @param zipFunction * @return */ public static Stream zip(final DoubleIterator a, final DoubleIterator b, final DoubleBiFunction zipFunction) { return new IteratorStream<>(new ObjIteratorEx() { private final DoubleIterator iterA = a == null ? DoubleIterator.empty() : a; private final DoubleIterator iterB = b == null ? DoubleIterator.empty() : b; @Override public boolean hasNext() { return iterA.hasNext() && iterB.hasNext(); } @Override public R next() { return zipFunction.apply(iterA.nextDouble(), iterB.nextDouble()); } }); } /** * 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 * @param a * @param b * @param c * @param zipFunction * @return */ public static Stream zip(final DoubleIterator a, final DoubleIterator b, final DoubleIterator c, final DoubleTriFunction zipFunction) { return new IteratorStream<>(new ObjIteratorEx() { private final DoubleIterator iterA = a == null ? DoubleIterator.empty() : a; private final DoubleIterator iterB = b == null ? DoubleIterator.empty() : b; private final DoubleIterator iterC = c == null ? DoubleIterator.empty() : c; @Override public boolean hasNext() { return iterA.hasNext() && iterB.hasNext() && iterC.hasNext(); } @Override public R next() { return zipFunction.apply(iterA.nextDouble(), iterB.nextDouble(), iterC.nextDouble()); } }); } /** * 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 * @param a * @param b * @param zipFunction * @return */ public static Stream zip(final DoubleStream a, final DoubleStream b, final DoubleBiFunction zipFunction) { return ((Stream) zip(iterate(a), iterate(b), zipFunction)).onClose(newCloseHandler(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 * @param a * @param b * @param c * @param zipFunction * @return */ public static Stream zip(final DoubleStream a, final DoubleStream b, final DoubleStream c, final DoubleTriFunction zipFunction) { return ((Stream) zip(iterate(a), iterate(b), iterate(c), zipFunction)).onClose(newCloseHandler(Array.asList(a, b, c))); } /** * Zip together the iterators until one of them runs out of values. * Each array of values is combined into a single value using the supplied zipFunction function. * * @param * @param c * @param zipFunction * @return */ @SuppressWarnings("resource") public static Stream zip(final Collection c, final DoubleNFunction zipFunction) { if (N.isNullOrEmpty(c)) { return Stream.empty(); } final int len = c.size(); final DoubleIterator[] iters = new DoubleIterator[len]; int i = 0; for (DoubleStream s : c) { iters[i++] = iterate(s); } return new IteratorStream<>(new ObjIteratorEx() { @Override public boolean hasNext() { for (int i = 0; i < len; i++) { if (!iters[i].hasNext()) { return false; } } return true; } @Override public R next() { final double[] args = new double[len]; for (int i = 0; i < len; i++) { args[i] = iters[i].nextDouble(); } return zipFunction.apply(args); } }).onClose(newCloseHandler(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 * @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 Stream zip(final double[] a, final double[] b, final double valueForNoneA, final double valueForNoneB, final DoubleBiFunction zipFunction) { return zip(DoubleIteratorEx.of(a), DoubleIteratorEx.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 * @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 Stream zip(final double[] a, final double[] b, final double[] c, final double valueForNoneA, final double valueForNoneB, final double valueForNoneC, final DoubleTriFunction zipFunction) { return zip(DoubleIteratorEx.of(a), DoubleIteratorEx.of(b), DoubleIteratorEx.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 * @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 Stream zip(final DoubleIterator a, final DoubleIterator b, final double valueForNoneA, final double valueForNoneB, final DoubleBiFunction zipFunction) { return new IteratorStream<>(new ObjIteratorEx() { private final DoubleIterator iterA = a == null ? DoubleIterator.empty() : a; private final DoubleIterator iterB = b == null ? DoubleIterator.empty() : b; @Override public boolean hasNext() { return iterA.hasNext() || iterB.hasNext(); } @Override public R next() { if (iterA.hasNext()) { return zipFunction.apply(iterA.nextDouble(), iterB.hasNext() ? iterB.nextDouble() : valueForNoneB); } else { return zipFunction.apply(valueForNoneA, iterB.nextDouble()); } } }); } /** * 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 * @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 Stream zip(final DoubleIterator a, final DoubleIterator b, final DoubleIterator c, final double valueForNoneA, final double valueForNoneB, final double valueForNoneC, final DoubleTriFunction zipFunction) { return new IteratorStream<>(new ObjIteratorEx() { private final DoubleIterator iterA = a == null ? DoubleIterator.empty() : a; private final DoubleIterator iterB = b == null ? DoubleIterator.empty() : b; private final DoubleIterator iterC = c == null ? DoubleIterator.empty() : c; @Override public boolean hasNext() { return iterA.hasNext() || iterB.hasNext() || iterC.hasNext(); } @Override public R next() { if (iterA.hasNext()) { return zipFunction.apply(iterA.nextDouble(), iterB.hasNext() ? iterB.nextDouble() : valueForNoneB, iterC.hasNext() ? iterC.nextDouble() : valueForNoneC); } else if (iterB.hasNext()) { return zipFunction.apply(valueForNoneA, iterB.nextDouble(), iterC.hasNext() ? iterC.nextDouble() : valueForNoneC); } else { return zipFunction.apply(valueForNoneA, valueForNoneB, iterC.nextDouble()); } } }); } /** * 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 * @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 Stream zip(final DoubleStream a, final DoubleStream b, final double valueForNoneA, final double valueForNoneB, final DoubleBiFunction zipFunction) { return ((Stream) zip(iterate(a), iterate(b), valueForNoneA, valueForNoneB, zipFunction)).onClose(newCloseHandler(a, b)); } /** * 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 * @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 Stream zip(final DoubleStream a, final DoubleStream b, final DoubleStream c, final double valueForNoneA, final double valueForNoneB, final double valueForNoneC, final DoubleTriFunction zipFunction) { return ((Stream) zip(iterate(a), iterate(b), iterate(c), valueForNoneA, valueForNoneB, valueForNoneC, zipFunction)) .onClose(newCloseHandler(Array.asList(a, b, c))); } /** * Zip together the iterators until all of them runs out of values. * Each array of values is combined into a single value using the supplied zipFunction function. * * @param * @param c * @param valuesForNone value to fill for any iterator runs out of values. * @param zipFunction * @return */ @SuppressWarnings("resource") public static Stream zip(final Collection c, final double[] valuesForNone, final DoubleNFunction zipFunction) { if (N.isNullOrEmpty(c)) { return Stream.empty(); } final int len = c.size(); if (len != valuesForNone.length) { throw new IllegalArgumentException("The size of 'valuesForNone' must be same as the size of the collection of iterators"); } final DoubleStream[] ss = c.toArray(new DoubleStream[len]); final DoubleIterator[] iters = new DoubleIterator[len]; for (int i = 0; i < len; i++) { iters[i] = iterate(ss[i]); } return new IteratorStream<>(new ObjIteratorEx() { @Override public boolean hasNext() { for (int i = 0; i < len; i++) { if (iters[i] != null) { if (iters[i].hasNext()) { return true; } else if (iters[i] != null) { iters[i] = null; ss[i].close(); } } } return false; } @Override public R next() { final double[] args = new double[len]; boolean hasNext = false; for (int i = 0; i < len; i++) { if (iters[i] != null && iters[i].hasNext()) { hasNext = true; args[i] = iters[i].nextDouble(); } else { args[i] = valuesForNone[i]; } } if (!hasNext) { throw new NoSuchElementException(); } return zipFunction.apply(args); } }).onClose(newCloseHandler(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
* @param * @param * @param a * @param b * @param zipFunction * @return */ public static Stream zip(final A[] a, final B[] b, final BiFunction zipFunction) { return zip(ObjIteratorEx.of(a), ObjIteratorEx.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 * @param * @param * @param * @param a * @param b * @param c * @param zipFunction * @return */ public static Stream zip(final A[] a, final B[] b, final C[] c, final TriFunction zipFunction) { return zip(ObjIteratorEx.of(a), ObjIteratorEx.of(b), ObjIteratorEx.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 * @param * @param * @param a * @param b * @param zipFunction * @return */ public static Stream zip(final Iterable a, final Iterable b, final 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 * @param * @param * @param * @param a * @param b * @param c * @param zipFunction * @return */ public static Stream zip(final Iterable a, final Iterable b, final Iterable c, final 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 * @param * @param * @param a * @param b * @param zipFunction * @return */ public static Stream zip(final Iterator a, final Iterator b, final BiFunction zipFunction) { return new IteratorStream<>(new ObjIteratorEx() { private final Iterator iterA = a == null ? ObjIterator. empty() : (Iterator) a; private final Iterator iterB = b == null ? ObjIterator. empty() : (Iterator) b; @Override public boolean hasNext() { return iterA.hasNext() && iterB.hasNext(); } @Override public R next() { return zipFunction.apply(iterA.next(), iterB.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 * @param * @param * @param * @param a * @param b * @param c * @param zipFunction * @return */ public static Stream zip(final Iterator a, final Iterator b, final Iterator c, final TriFunction zipFunction) { return new IteratorStream<>(new ObjIteratorEx() { private final Iterator iterA = a == null ? ObjIterator. empty() : (Iterator) a; private final Iterator iterB = b == null ? ObjIterator. empty() : (Iterator) b; private final Iterator iterC = c == null ? ObjIterator. empty() : (Iterator) c; @Override public boolean hasNext() { return iterA.hasNext() && iterB.hasNext() && iterC.hasNext(); } @Override public R next() { return zipFunction.apply(iterA.next(), iterB.next(), iterC.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 * @param * @param * @param a * @param b * @param zipFunction * @return */ public static Stream zip(final Stream a, final Stream b, final BiFunction zipFunction) { return ((Stream) zip(iterate(a), iterate(b), zipFunction)).onClose(newCloseHandler(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 * @param * @param * @param * @param a * @param b * @param c * @param zipFunction * @return */ public static Stream zip(final Stream a, final Stream b, final Stream c, final TriFunction zipFunction) { return ((Stream) zip(iterate(a), iterate(b), iterate(c), zipFunction)).onClose(newCloseHandler(Array.asList(a, b, c))); } /** * Zip together the iterators until one of them runs out of values. * Each array of values is combined into a single value using the supplied zipFunction function. * * @param * @param * @param c * @param zipFunction * @return */ public static Stream zip(final Collection> c, final Function, ? extends R> zipFunction) { if (N.isNullOrEmpty(c)) { return Stream.empty(); } final int len = c.size(); final List> iterList = new ArrayList<>(len); for (Stream s : c) { iterList.add(iterate(s)); } return ((Stream) zipIterators(iterList, zipFunction)).onClose(newCloseHandler(c)); } /** * * * @param * @param * @param collections * @param zipFunction * @return */ public static Stream zipIterables(final Collection> collections, final Function, ? extends R> zipFunction) { if (N.isNullOrEmpty(collections)) { return Stream.empty(); } final int len = collections.size(); final List> iterList = new ArrayList<>(len); for (Iterable e : collections) { iterList.add(ObjIterator.of(e)); } return zipIterators(iterList, zipFunction); } /** * * * @param * @param * @param iterators * @param zipFunction * @return */ public static Stream zipIterators(final Collection> iterators, final Function, ? extends R> zipFunction) { if (N.isNullOrEmpty(iterators)) { return Stream.empty(); } final int len = iterators.size(); final Iterator[] iters = iterators.toArray(new Iterator[len]); return new IteratorStream<>(new ObjIteratorEx() { @Override public boolean hasNext() { for (int i = 0; i < len; i++) { if (!iters[i].hasNext()) { return false; } } return true; } @Override public R next() { final Object[] args = new Object[len]; for (int i = 0; i < len; i++) { args[i] = iters[i].next(); } return zipFunction.apply(Arrays.asList((T[]) args)); } }); } /** * 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 * @param * @param * @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 Stream zip(final A[] a, final B[] b, final A valueForNoneA, final B valueForNoneB, final BiFunction zipFunction) { return zip(ObjIteratorEx.of(a), ObjIteratorEx.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 * @param * @param * @param * @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 Stream zip(final A[] a, final B[] b, final C[] c, final A valueForNoneA, final B valueForNoneB, final C valueForNoneC, final TriFunction zipFunction) { return zip(ObjIteratorEx.of(a), ObjIteratorEx.of(b), ObjIteratorEx.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 * @param * @param * @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 Stream zip(final Iterable a, final Iterable b, final A valueForNoneA, final B valueForNoneB, final 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 * @param * @param * @param * @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 Stream zip(final Iterable a, final Iterable b, final Iterable c, final A valueForNoneA, final B valueForNoneB, final C valueForNoneC, final 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 * @param * @param * @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 Stream zip(final Iterator a, final Iterator b, final A valueForNoneA, final B valueForNoneB, final BiFunction zipFunction) { return new IteratorStream<>(new ObjIteratorEx() { private final Iterator iterA = a == null ? ObjIterator. empty() : (Iterator) a; private final Iterator iterB = b == null ? ObjIterator. empty() : (Iterator) b; @Override public boolean hasNext() { return iterA.hasNext() || iterB.hasNext(); } @Override public R next() { if (iterA.hasNext()) { return zipFunction.apply(iterA.next(), iterB.hasNext() ? iterB.next() : valueForNoneB); } else { return zipFunction.apply(valueForNoneA, iterB.next()); } } }); } /** * 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 * @param * @param * @param * @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 Stream zip(final Iterator a, final Iterator b, final Iterator c, final A valueForNoneA, final B valueForNoneB, final C valueForNoneC, final TriFunction zipFunction) { return new IteratorStream<>(new ObjIteratorEx() { private final Iterator iterA = a == null ? ObjIterator. empty() : (Iterator) a; private final Iterator iterB = b == null ? ObjIterator. empty() : (Iterator) b; private final Iterator iterC = c == null ? ObjIterator. empty() : (Iterator) c; @Override public boolean hasNext() { return iterA.hasNext() || iterB.hasNext() || iterC.hasNext(); } @Override public R next() { if (iterA.hasNext()) { return zipFunction.apply(iterA.next(), iterB.hasNext() ? iterB.next() : valueForNoneB, iterC.hasNext() ? iterC.next() : valueForNoneC); } else if (iterB.hasNext()) { return zipFunction.apply(valueForNoneA, iterB.next(), iterC.hasNext() ? iterC.next() : valueForNoneC); } else { return zipFunction.apply(valueForNoneA, valueForNoneB, iterC.next()); } } }); } /** * 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 * @param * @param * @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 Stream zip(final Stream a, final Stream b, final A valueForNoneA, final B valueForNoneB, final BiFunction zipFunction) { return ((Stream) zip(iterate(a), iterate(b), valueForNoneA, valueForNoneB, zipFunction)).onClose(newCloseHandler(a, b)); } /** * 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 * @param * @param * @param * @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 Stream zip(final Stream a, final Stream b, final Stream c, final A valueForNoneA, final B valueForNoneB, final C valueForNoneC, final TriFunction zipFunction) { return ((Stream) zip(iterate(a), iterate(b), iterate(c), valueForNoneA, valueForNoneB, valueForNoneC, zipFunction)) .onClose(newCloseHandler(Array.asList(a, b, c))); } /** * Zip together the iterators until all of them runs out of values. * Each array of values is combined into a single value using the supplied zipFunction function. * * @param * @param * @param c * @param valuesForNone value to fill for any iterator runs out of values. * @param zipFunction * @return */ public static Stream zip(final Collection> c, final List valuesForNone, final Function, ? extends R> zipFunction) { if (N.isNullOrEmpty(c)) { return Stream.empty(); } final int len = c.size(); if (len != valuesForNone.size()) { throw new IllegalArgumentException("The size of 'valuesForNone' must be same as the size of the collection of iterators"); } final Stream[] ss = c.toArray(new Stream[len]); final ObjIterator[] iters = new ObjIterator[len]; for (int i = 0; i < len; i++) { iters[i] = iterate(ss[i]); } return new IteratorStream<>(new ObjIteratorEx() { @Override public boolean hasNext() { for (int i = 0; i < len; i++) { if (iters[i] != null) { if (iters[i].hasNext()) { return true; } else if (iters[i] != null) { iters[i] = null; ss[i].close(); } } } return false; } @Override public R next() { final Object[] args = new Object[len]; boolean hasNext = false; for (int i = 0; i < len; i++) { if (iters[i] != null && iters[i].hasNext()) { hasNext = true; args[i] = iters[i].next(); } else { args[i] = valuesForNone.get(i); } } if (!hasNext) { throw new NoSuchElementException(); } return zipFunction.apply(Arrays.asList((T[]) args)); } }); } /** * * @param * @param * @param collections * @param valuesForNone * @param zipFunction * @return */ public static Stream zipIterables(final Collection> collections, final List valuesForNone, Function, ? extends R> zipFunction) { if (N.isNullOrEmpty(collections)) { return Stream.empty(); } final int len = collections.size(); if (len != valuesForNone.size()) { throw new IllegalArgumentException("The size of 'valuesForNone' must be same as the size of the collection of iterators"); } final List> iterList = new ArrayList<>(len); for (Iterable e : collections) { iterList.add(N.iterate(e)); } return zipIterators(iterList, valuesForNone, zipFunction); } /** * * * @param * @param * @param iterators * @param valuesForNone value to fill for any iterator runs out of values. * @param zipFunction * @return */ public static Stream zipIterators(final Collection> iterators, final List valuesForNone, final Function, ? extends R> zipFunction) { if (N.isNullOrEmpty(iterators)) { return Stream.empty(); } final int len = iterators.size(); if (len != valuesForNone.size()) { throw new IllegalArgumentException("The size of 'valuesForNone' must be same as the size of the collection of iterators"); } final Iterator[] iters = iterators.toArray(new Iterator[len]); return new IteratorStream<>(new ObjIteratorEx() { @Override public boolean hasNext() { for (int i = 0; i < len; i++) { if (iters[i] != null) { if (iters[i].hasNext()) { return true; } else if (iters[i] != null) { iters[i] = null; } } } return false; } @Override public R next() { final Object[] args = new Object[len]; boolean hasNext = false; for (int i = 0; i < len; i++) { if (iters[i] != null && iters[i].hasNext()) { hasNext = true; args[i] = iters[i].next(); } else { args[i] = valuesForNone.get(i); } } if (!hasNext) { throw new NoSuchElementException(); } return zipFunction.apply(Arrays.asList((T[]) args)); } }); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param * @param a * @param b * @param zipFunction * @return */ public static Stream parallelZip(final Iterable a, final Iterable b, final BiFunction zipFunction) { return parallelZip(a, b, zipFunction, DEFAULT_BUFFERED_SIZE_PER_ITERATOR); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param * @param a * @param b * @param zipFunction * @param bufferSize * @return */ public static Stream parallelZip(final Iterable a, final Iterable b, final BiFunction zipFunction, final int bufferSize) { return parallelZip(N.iterate(a), N.iterate(b), zipFunction, bufferSize); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param * @param * @param a * @param b * @param c * @param zipFunction * @return */ public static Stream parallelZip(final Iterable a, final Iterable b, final Iterable c, final TriFunction zipFunction) { return parallelZip(a, b, c, zipFunction, DEFAULT_BUFFERED_SIZE_PER_ITERATOR); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param * @param * @param a * @param b * @param c * @param zipFunction * @param bufferSize * @return */ public static Stream parallelZip(final Iterable a, final Iterable b, final Iterable c, final TriFunction zipFunction, final int bufferSize) { return parallelZip(N.iterate(a), N.iterate(b), N.iterate(c), zipFunction, bufferSize); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param * @param a * @param b * @param zipFunction * @return * @see #parallelZip(Iterator, Iterator, BiFunction, int, int) */ public static Stream parallelZip(final Iterator a, final Iterator b, final BiFunction zipFunction) { return parallelZip(a, b, zipFunction, DEFAULT_BUFFERED_SIZE_PER_ITERATOR); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param * @param a * @param b * @param zipFunction * @param bufferSize * @return * @see #parallelZip(Iterator, Iterator, BiFunction, int, int) */ public static Stream parallelZip(final Iterator a, final Iterator b, final BiFunction zipFunction, final int bufferSize) { return parallelZip(a, b, zipFunction, bufferSize, 0); } /** * * @param * @param * @param * @param a * @param b * @param zipFunction * @param bufferSize * @param maxThreadNumForZipFunction * @return */ public static Stream parallelZip(final Iterator a, final Iterator b, final BiFunction zipFunction, final int bufferSize, final int maxThreadNumForZipFunction) { final Supplier> supplier = () -> { final AtomicInteger threadCounterA = new AtomicInteger(1); final AtomicInteger threadCounterB = new AtomicInteger(1); final BlockingQueue queueA = new ArrayBlockingQueue<>(bufferSize); final BlockingQueue queueB = new ArrayBlockingQueue<>(bufferSize); final Holder eHolder = new Holder<>(); final MutableBoolean onGoing = MutableBoolean.of(true); final Holder holderForAsyncExecutorUsed = new Holder<>(); boolean noException = false; try { readToQueue(a, b, DEFAULT_ASYNC_EXECUTOR, threadCounterA, threadCounterB, queueA, queueB, eHolder, onGoing, holderForAsyncExecutorUsed); noException = true; } finally { if (!noException) { onGoing.setFalse(); } } if (eHolder.value() != null) { setStopFlagAndThrowException(eHolder, onGoing); } final Deque closeHandlers = new LocalArrayDeque<>(1); closeHandlers.add(() -> { onGoing.setFalse(); if (holderForAsyncExecutorUsed.isNotNull()) { shutdownTempExecutor(holderForAsyncExecutorUsed.value()); } }); final IntFunction> iterCreator = taskIdx -> new ObjIteratorEx<>() { private A nextA = null; private B nextB = null; @Override public boolean hasNext() { if (nextA == null && nextB == null) { try { while (nextA == null && onGoing.value() && (threadCounterA.get() > 0 || queueA.size() > 0)) { // (threadCounterA.get() > 0 || queueA.size() > 0) is wrong. has to check counter first nextA = queueA.poll(MAX_WAIT_TIME_FOR_QUEUE_POLL, TimeUnit.MILLISECONDS); } if (nextA == null) { onGoing.setFalse(); return false; } while (nextB == null && onGoing.value() && (threadCounterB.get() > 0 || queueB.size() > 0)) { // (threadCounterB.get() > 0 || queueB.size() > 0) is wrong. has to check counter first nextB = queueB.poll(MAX_WAIT_TIME_FOR_QUEUE_POLL, TimeUnit.MILLISECONDS); } if (nextB == null) { onGoing.setFalse(); return false; } } catch (Exception e) { setError(eHolder, e, onGoing); } if (eHolder.value() != null) { setStopFlagAndThrowException(eHolder, onGoing); } } return nextA != null && nextB != null; } @Override public R next() { if ((nextA == null || nextB == null) && !hasNext()) { throw new NoSuchElementException(); } R result = null; try { result = zipFunction.apply(nextA == NONE ? null : nextA, nextB == NONE ? null : nextB); nextA = null; nextB = null; } catch (Exception e) { setError(eHolder, e, onGoing); } if (eHolder.value() != null) { setStopFlagAndThrowException(eHolder, onGoing); } return result; } }; final int maxThreadNum = checkMaxThreadNum(maxThreadNumForZipFunction, 0, DEFAULT_ASYNC_EXECUTOR); if (maxThreadNum <= 1) { final Iterator iter = iterCreator.apply(0); return new IteratorStream<>(iter, false, null, closeHandlers); } else { final List> iters = new ArrayList<>(maxThreadNum); for (int i = 0; i < maxThreadNum; i++) { iters.add(iterCreator.apply(i)); } return new IteratorStream<>(parallelConcatIterators(iters, iters.size(), 0, false, DEFAULT_ASYNC_EXECUTOR), false, null, closeHandlers); } }; return just(supplier).flatMap(Supplier::get); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param * @param * @param a * @param b * @param c * @param zipFunction * @return */ public static Stream parallelZip(final Iterator a, final Iterator b, final Iterator c, final TriFunction zipFunction) { return parallelZip(a, b, c, zipFunction, DEFAULT_BUFFERED_SIZE_PER_ITERATOR); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param * @param * @param a * @param b * @param c * @param zipFunction * @param bufferSize * @return */ public static Stream parallelZip(final Iterator a, final Iterator b, final Iterator c, final TriFunction zipFunction, final int bufferSize) { return parallelZip(a, b, c, zipFunction, bufferSize, 0); } /** * * @param * @param * @param * @param * @param a * @param b * @param c * @param zipFunction * @param bufferSize * @param maxThreadNumForZipFunction * @return */ public static Stream parallelZip(final Iterator a, final Iterator b, final Iterator c, final TriFunction zipFunction, final int bufferSize, final int maxThreadNumForZipFunction) { final Supplier> supplier = () -> { final AtomicInteger threadCounterA = new AtomicInteger(1); final AtomicInteger threadCounterB = new AtomicInteger(1); final AtomicInteger threadCounterC = new AtomicInteger(1); final BlockingQueue queueA = new ArrayBlockingQueue<>(bufferSize); final BlockingQueue queueB = new ArrayBlockingQueue<>(bufferSize); final BlockingQueue queueC = new ArrayBlockingQueue<>(bufferSize); final Holder eHolder = new Holder<>(); final MutableBoolean onGoing = MutableBoolean.of(true); final Holder holderForAsyncExecutorUsed = new Holder<>(); boolean noException = false; try { readToQueue(a, b, c, DEFAULT_ASYNC_EXECUTOR, threadCounterA, threadCounterB, threadCounterC, queueA, queueB, queueC, eHolder, onGoing, holderForAsyncExecutorUsed); noException = true; } finally { if (!noException) { onGoing.setFalse(); } } if (eHolder.value() != null) { setStopFlagAndThrowException(eHolder, onGoing); } final Deque closeHandlers = new LocalArrayDeque<>(1); closeHandlers.add(() -> { onGoing.setFalse(); if (holderForAsyncExecutorUsed.isNotNull()) { shutdownTempExecutor(holderForAsyncExecutorUsed.value()); } }); final IntFunction> iterCreator = taskIdx -> new ObjIteratorEx<>() { private A nextA = null; private B nextB = null; private C nextC = null; @Override public boolean hasNext() { if (nextA == null && nextB == null && nextC == null) { try { while (nextA == null && onGoing.value() && (threadCounterA.get() > 0 || queueA.size() > 0)) { // (threadCounterA.get() > 0 || queueA.size() > 0) is wrong. has to check counter first nextA = queueA.poll(MAX_WAIT_TIME_FOR_QUEUE_POLL, TimeUnit.MILLISECONDS); } if (nextA == null) { onGoing.setFalse(); return false; } while (nextB == null && onGoing.value() && (threadCounterB.get() > 0 || queueB.size() > 0)) { // (threadCounterB.get() > 0 || queueB.size() > 0) is wrong. has to check counter first nextB = queueB.poll(MAX_WAIT_TIME_FOR_QUEUE_POLL, TimeUnit.MILLISECONDS); } if (nextB == null) { onGoing.setFalse(); return false; } while (nextC == null && onGoing.value() && (threadCounterC.get() > 0 || queueC.size() > 0)) { // (threadCounterC.get() > 0 || queueC.size() > 0) is wrong. has to check counter first nextC = queueC.poll(MAX_WAIT_TIME_FOR_QUEUE_POLL, TimeUnit.MILLISECONDS); } if (nextC == null) { onGoing.setFalse(); return false; } } catch (Exception e) { setError(eHolder, e, onGoing); } if (eHolder.value() != null) { setStopFlagAndThrowException(eHolder, onGoing); } } return nextA != null && nextB != null && nextC != null; } @Override public R next() { if ((nextA == null || nextB == null || nextC == null) && !hasNext()) { throw new NoSuchElementException(); } R result = null; try { result = zipFunction.apply(nextA == NONE ? null : nextA, nextB == NONE ? null : nextB, nextC == NONE ? null : nextC); nextA = null; nextB = null; nextC = null; } catch (Exception e) { setError(eHolder, e, onGoing); } if (eHolder.value() != null) { setStopFlagAndThrowException(eHolder, onGoing); } return result; } }; final int maxThreadNum = checkMaxThreadNum(maxThreadNumForZipFunction, 0, DEFAULT_ASYNC_EXECUTOR); if (maxThreadNum <= 1) { final Iterator iter = iterCreator.apply(0); return new IteratorStream<>(iter, false, null, closeHandlers); } else { final List> iters = new ArrayList<>(maxThreadNum); for (int i = 0; i < maxThreadNum; i++) { iters.add(iterCreator.apply(i)); } return new IteratorStream<>(parallelConcatIterators(iters, iters.size(), 0, false, DEFAULT_ASYNC_EXECUTOR), false, null, closeHandlers); } }; return just(supplier).flatMap(Supplier::get); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param * @param a * @param b * @param zipFunction * @return */ public static Stream parallelZip(final Stream a, final Stream b, final BiFunction zipFunction) { return parallelZip(a, b, zipFunction, DEFAULT_BUFFERED_SIZE_PER_ITERATOR); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param * @param a * @param b * @param zipFunction * @param bufferSize * @return */ public static Stream parallelZip(final Stream a, final Stream b, final BiFunction zipFunction, final int bufferSize) { return ((Stream) parallelZip(iterate(a), iterate(b), zipFunction, bufferSize)).onClose(newCloseHandler(a, b)); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param * @param * @param a * @param b * @param c * @param zipFunction * @return */ public static Stream parallelZip(final Stream a, final Stream b, final Stream c, final TriFunction zipFunction) { return parallelZip(a, b, c, zipFunction, DEFAULT_BUFFERED_SIZE_PER_ITERATOR); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param * @param * @param a * @param b * @param c * @param zipFunction * @param bufferSize * @return */ public static Stream parallelZip(final Stream a, final Stream b, final Stream c, final TriFunction zipFunction, final int bufferSize) { return ((Stream) parallelZip(iterate(a), iterate(b), iterate(c), zipFunction, bufferSize)).onClose(newCloseHandler(Array.asList(a, b, c))); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param c * @param zipFunction * @return */ public static Stream parallelZip(final Collection> c, final Function, ? extends R> zipFunction) { return parallelZip(c, zipFunction, DEFAULT_BUFFERED_SIZE_PER_ITERATOR); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param c * @param zipFunction * @param bufferSize * @return */ public static Stream parallelZip(final Collection> c, final Function, ? extends R> zipFunction, final int bufferSize) { if (N.isNullOrEmpty(c)) { return Stream.empty(); } final int len = c.size(); final List> iterList = new ArrayList<>(len); for (Stream s : c) { iterList.add(iterate(s)); } return ((Stream) parallelZipIterators(iterList, zipFunction, bufferSize)).onClose(newCloseHandler(c)); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param * @param a * @param b * @param valueForNoneA * @param valueForNoneB * @param zipFunction * @return */ public static Stream parallelZip(final Iterable a, final Iterable b, final A valueForNoneA, final B valueForNoneB, final BiFunction zipFunction) { return parallelZip(a, b, valueForNoneA, valueForNoneB, zipFunction, DEFAULT_BUFFERED_SIZE_PER_ITERATOR); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param * @param a * @param b * @param valueForNoneA * @param valueForNoneB * @param zipFunction * @param bufferSize * @return */ public static Stream parallelZip(final Iterable a, final Iterable b, final A valueForNoneA, final B valueForNoneB, final BiFunction zipFunction, final int bufferSize) { return parallelZip(N.iterate(a), N.iterate(b), valueForNoneA, valueForNoneB, zipFunction, bufferSize); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param * @param * @param a * @param b * @param c * @param valueForNoneA * @param valueForNoneB * @param valueForNoneC * @param zipFunction * @return */ public static Stream parallelZip(final Iterable a, final Iterable b, final Iterable c, final A valueForNoneA, final B valueForNoneB, final C valueForNoneC, final TriFunction zipFunction) { return parallelZip(a, b, c, valueForNoneA, valueForNoneB, valueForNoneC, zipFunction, DEFAULT_BUFFERED_SIZE_PER_ITERATOR); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param * @param * @param a * @param b * @param c * @param valueForNoneA * @param valueForNoneB * @param valueForNoneC * @param zipFunction * @param bufferSize * @return */ public static Stream parallelZip(final Iterable a, final Iterable b, final Iterable c, final A valueForNoneA, final B valueForNoneB, final C valueForNoneC, final TriFunction zipFunction, final int bufferSize) { return parallelZip(N.iterate(a), N.iterate(b), N.iterate(c), valueForNoneA, valueForNoneB, valueForNoneC, zipFunction, bufferSize); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param * @param a * @param b * @param valueForNoneA * @param valueForNoneB * @param zipFunction * @return * @see #parallelZip(Iterator, Iterator, Object, Object, BiFunction, int, int) */ public static Stream parallelZip(final Iterator a, final Iterator b, final A valueForNoneA, final B valueForNoneB, final BiFunction zipFunction) { return parallelZip(a, b, valueForNoneA, valueForNoneB, zipFunction, DEFAULT_BUFFERED_SIZE_PER_ITERATOR); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param * @param a * @param b * @param valueForNoneA * @param valueForNoneB * @param zipFunction * @param bufferSize * @return * @see #parallelZip(Iterator, Iterator, Object, Object, BiFunction, int, int) */ public static Stream parallelZip(final Iterator a, final Iterator b, final A valueForNoneA, final B valueForNoneB, final BiFunction zipFunction, final int bufferSize) { return parallelZip(a, b, valueForNoneA, valueForNoneB, zipFunction, bufferSize, 0); } /** * * @param * @param * @param * @param a * @param b * @param valueForNoneA * @param valueForNoneB * @param zipFunction * @param bufferSize * @param maxThreadNumForZipFunction * @return */ public static Stream parallelZip(final Iterator a, final Iterator b, final A valueForNoneA, final B valueForNoneB, final BiFunction zipFunction, final int bufferSize, final int maxThreadNumForZipFunction) { final Supplier> supplier = () -> { final AtomicInteger threadCounterA = new AtomicInteger(1); final AtomicInteger threadCounterB = new AtomicInteger(1); final BlockingQueue queueA = new ArrayBlockingQueue<>(bufferSize); final BlockingQueue queueB = new ArrayBlockingQueue<>(bufferSize); final Holder eHolder = new Holder<>(); final MutableBoolean onGoing = MutableBoolean.of(true); final Holder holderForAsyncExecutorUsed = new Holder<>(); boolean noException = false; try { readToQueue(a, b, DEFAULT_ASYNC_EXECUTOR, threadCounterA, threadCounterB, queueA, queueB, eHolder, onGoing, holderForAsyncExecutorUsed); noException = true; } finally { if (!noException) { onGoing.setFalse(); } } if (eHolder.value() != null) { setStopFlagAndThrowException(eHolder, onGoing); } final Deque closeHandlers = new LocalArrayDeque<>(1); closeHandlers.add(() -> { onGoing.setFalse(); if (holderForAsyncExecutorUsed.isNotNull()) { shutdownTempExecutor(holderForAsyncExecutorUsed.value()); } }); final IntFunction> iterCreator = taskIdx -> new ObjIteratorEx<>() { private A nextA = null; private B nextB = null; @Override public boolean hasNext() { if (nextA == null && nextB == null) { try { while (nextA == null && onGoing.value() && (threadCounterA.get() > 0 || queueA.size() > 0)) { // (threadCounterA.get() > 0 || queueA.size() > 0) is wrong. has to check counter first nextA = queueA.poll(MAX_WAIT_TIME_FOR_QUEUE_POLL, TimeUnit.MILLISECONDS); } while (nextB == null && onGoing.value() && (threadCounterB.get() > 0 || queueB.size() > 0)) { // (threadCounterB.get() > 0 || queueB.size() > 0) is wrong. has to check counter first nextB = queueB.poll(MAX_WAIT_TIME_FOR_QUEUE_POLL, TimeUnit.MILLISECONDS); } } catch (Exception e) { setError(eHolder, e, onGoing); } if (eHolder.value() != null) { setStopFlagAndThrowException(eHolder, onGoing); } } if (nextA != null || nextB != null) { return true; } else { onGoing.setFalse(); return false; } } @Override public R next() { if ((nextA == null && nextB == null) && !hasNext()) { throw new NoSuchElementException(); } nextA = nextA == NONE ? null : (nextA == null ? valueForNoneA : nextA); nextB = nextB == NONE ? null : (nextB == null ? valueForNoneB : nextB); R result = null; try { result = zipFunction.apply(nextA, nextB); nextA = null; nextB = null; } catch (Exception e) { setError(eHolder, e, onGoing); } if (eHolder.value() != null) { setStopFlagAndThrowException(eHolder, onGoing); } return result; } }; final int maxThreadNum = checkMaxThreadNum(maxThreadNumForZipFunction, 0, DEFAULT_ASYNC_EXECUTOR); if (maxThreadNum <= 1) { final Iterator iter = iterCreator.apply(0); return new IteratorStream<>(iter, false, null, closeHandlers); } else { final List> iters = new ArrayList<>(maxThreadNum); for (int i = 0; i < maxThreadNum; i++) { iters.add(iterCreator.apply(i)); } return new IteratorStream<>(parallelConcatIterators(iters, iters.size(), 0, false, DEFAULT_ASYNC_EXECUTOR), false, null, closeHandlers); } }; return just(supplier).flatMap(Supplier::get); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param * @param * @param a * @param b * @param c * @param valueForNoneA * @param valueForNoneB * @param valueForNoneC * @param zipFunction * @return * @see #parallelZip(Iterator, Iterator, Iterator, Object, Object, Object, TriFunction, int, int) */ public static Stream parallelZip(final Iterator a, final Iterator b, final Iterator c, final A valueForNoneA, final B valueForNoneB, final C valueForNoneC, final TriFunction zipFunction) { return parallelZip(a, b, c, valueForNoneA, valueForNoneB, valueForNoneC, zipFunction, DEFAULT_BUFFERED_SIZE_PER_ITERATOR); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param * @param * @param a * @param b * @param c * @param valueForNoneA * @param valueForNoneB * @param valueForNoneC * @param zipFunction * @param bufferSize * @return * @see #parallelZip(Iterator, Iterator, Iterator, Object, Object, Object, TriFunction, int, int) */ public static Stream parallelZip(final Iterator a, final Iterator b, final Iterator c, final A valueForNoneA, final B valueForNoneB, final C valueForNoneC, final TriFunction zipFunction, final int bufferSize) { return parallelZip(a, b, c, valueForNoneA, valueForNoneB, valueForNoneC, zipFunction, bufferSize, 0); } /** * * @param * @param * @param * @param * @param a * @param b * @param c * @param valueForNoneA * @param valueForNoneB * @param valueForNoneC * @param zipFunction * @param bufferSize * @param maxThreadNumForZipFunction * @return */ public static Stream parallelZip(final Iterator a, final Iterator b, final Iterator c, final A valueForNoneA, final B valueForNoneB, final C valueForNoneC, final TriFunction zipFunction, final int bufferSize, final int maxThreadNumForZipFunction) { final Supplier> supplier = () -> { final AtomicInteger threadCounterA = new AtomicInteger(1); final AtomicInteger threadCounterB = new AtomicInteger(1); final AtomicInteger threadCounterC = new AtomicInteger(1); final BlockingQueue queueA = new ArrayBlockingQueue<>(bufferSize); final BlockingQueue queueB = new ArrayBlockingQueue<>(bufferSize); final BlockingQueue queueC = new ArrayBlockingQueue<>(bufferSize); final Holder eHolder = new Holder<>(); final MutableBoolean onGoing = MutableBoolean.of(true); final Holder holderForAsyncExecutorUsed = new Holder<>(); boolean noException = false; try { readToQueue(a, b, c, DEFAULT_ASYNC_EXECUTOR, threadCounterA, threadCounterB, threadCounterC, queueA, queueB, queueC, eHolder, onGoing, holderForAsyncExecutorUsed); noException = true; } finally { if (!noException) { onGoing.setFalse(); } } if (eHolder.value() != null) { setStopFlagAndThrowException(eHolder, onGoing); } final Deque closeHandlers = new LocalArrayDeque<>(1); closeHandlers.add(() -> { onGoing.setFalse(); if (holderForAsyncExecutorUsed.isNotNull()) { shutdownTempExecutor(holderForAsyncExecutorUsed.value()); } }); final IntFunction> iterCreator = taskIdx -> new ObjIteratorEx<>() { private A nextA = null; private B nextB = null; private C nextC = null; @Override public boolean hasNext() { if (nextA == null && nextB == null && nextC == null) { try { while (nextA == null && onGoing.value() && (threadCounterA.get() > 0 || queueA.size() > 0)) { // (threadCounterA.get() > 0 || queueA.size() > 0) is wrong. has to check counter first nextA = queueA.poll(MAX_WAIT_TIME_FOR_QUEUE_POLL, TimeUnit.MILLISECONDS); } while (nextB == null && onGoing.value() && (threadCounterB.get() > 0 || queueB.size() > 0)) { // (threadCounterB.get() > 0 || queueB.size() > 0) is wrong. has to check counter first nextB = queueB.poll(MAX_WAIT_TIME_FOR_QUEUE_POLL, TimeUnit.MILLISECONDS); } while (nextC == null && onGoing.value() && (threadCounterC.get() > 0 || queueC.size() > 0)) { // (threadCounterC.get() > 0 || queueC.size() > 0) is wrong. has to check counter first nextC = queueC.poll(MAX_WAIT_TIME_FOR_QUEUE_POLL, TimeUnit.MILLISECONDS); } } catch (Exception e) { setError(eHolder, e, onGoing); } if (eHolder.value() != null) { setStopFlagAndThrowException(eHolder, onGoing); } } if (nextA != null || nextB != null || nextC != null) { return true; } else { onGoing.setFalse(); return false; } } @Override public R next() { if ((nextA == null && nextB == null && nextC == null) && !hasNext()) { throw new NoSuchElementException(); } nextA = nextA == NONE ? null : (nextA == null ? valueForNoneA : nextA); nextB = nextB == NONE ? null : (nextB == null ? valueForNoneB : nextB); nextC = nextC == NONE ? null : (nextC == null ? valueForNoneC : nextC); R result = null; try { result = zipFunction.apply(nextA, nextB, nextC); nextA = null; nextB = null; nextC = null; } catch (Exception e) { setError(eHolder, e, onGoing); } if (eHolder.value() != null) { setStopFlagAndThrowException(eHolder, onGoing); } return result; } }; final int maxThreadNum = checkMaxThreadNum(maxThreadNumForZipFunction, 0, DEFAULT_ASYNC_EXECUTOR); if (maxThreadNum <= 1) { final Iterator iter = iterCreator.apply(0); return new IteratorStream<>(iter, false, null, closeHandlers); } else { final List> iters = new ArrayList<>(maxThreadNum); for (int i = 0; i < maxThreadNum; i++) { iters.add(iterCreator.apply(i)); } return new IteratorStream<>(parallelConcatIterators(iters, iters.size(), 0, false, DEFAULT_ASYNC_EXECUTOR), false, null, closeHandlers); } }; return just(supplier).flatMap(Supplier::get); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param * @param a * @param b * @param valueForNoneA * @param valueForNoneB * @param zipFunction * @return */ public static Stream parallelZip(final Stream a, final Stream b, final A valueForNoneA, final B valueForNoneB, final BiFunction zipFunction) { return parallelZip(a, b, valueForNoneA, valueForNoneB, zipFunction, DEFAULT_BUFFERED_SIZE_PER_ITERATOR); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param * @param a * @param b * @param valueForNoneA * @param valueForNoneB * @param zipFunction * @param bufferSize * @return */ public static Stream parallelZip(final Stream a, final Stream b, final A valueForNoneA, final B valueForNoneB, final BiFunction zipFunction, final int bufferSize) { return ((Stream) parallelZip(iterate(a), iterate(b), valueForNoneA, valueForNoneB, zipFunction, bufferSize)).onClose(newCloseHandler(a, b)); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param * @param * @param a * @param b * @param c * @param valueForNoneA * @param valueForNoneB * @param valueForNoneC * @param zipFunction * @return */ public static Stream parallelZip(final Stream a, final Stream b, final Stream c, final A valueForNoneA, final B valueForNoneB, final C valueForNoneC, final TriFunction zipFunction) { return parallelZip(a, b, c, valueForNoneA, valueForNoneB, valueForNoneC, zipFunction, DEFAULT_BUFFERED_SIZE_PER_ITERATOR); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param * @param * @param a * @param b * @param c * @param valueForNoneA * @param valueForNoneB * @param valueForNoneC * @param zipFunction * @param bufferSize * @return */ public static Stream parallelZip(final Stream a, final Stream b, final Stream c, final A valueForNoneA, final B valueForNoneB, final C valueForNoneC, final TriFunction zipFunction, final int bufferSize) { return ((Stream) parallelZip(iterate(a), iterate(b), iterate(c), valueForNoneA, valueForNoneB, valueForNoneC, zipFunction, bufferSize)) .onClose(newCloseHandler(Array.asList(a, b, c))); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param c * @param valuesForNone * @param zipFunction * @return */ public static Stream parallelZip(final Collection> c, final List valuesForNone, Function, ? extends R> zipFunction) { return parallelZip(c, valuesForNone, zipFunction, DEFAULT_BUFFERED_SIZE_PER_ITERATOR); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param c * @param valuesForNone * @param zipFunction * @param bufferSize * @return */ public static Stream parallelZip(final Collection> c, final List valuesForNone, Function, ? extends R> zipFunction, final int bufferSize) { if (N.isNullOrEmpty(c)) { return Stream.empty(); } final int len = c.size(); if (len != valuesForNone.size()) { throw new IllegalArgumentException("The size of 'valuesForNone' must be same as the size of the collection of iterators"); } final List> iterList = new ArrayList<>(len); for (Stream s : c) { iterList.add(iterate(s)); } return ((Stream) parallelZipIterators(iterList, valuesForNone, zipFunction, bufferSize)).onClose(newCloseHandler(c)); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param collections * @param zipFunction * @return */ @Beta public static Stream parallelZipIterables(final Collection> collections, final Function, ? extends R> zipFunction) { return parallelZipIterables(collections, zipFunction, DEFAULT_BUFFERED_SIZE_PER_ITERATOR); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param collections * @param zipFunction * @param bufferSize * @return */ @Beta public static Stream parallelZipIterables(final Collection> collections, final Function, ? extends R> zipFunction, final int bufferSize) { if (N.isNullOrEmpty(collections)) { return Stream.empty(); } final int len = collections.size(); final List> iterList = new ArrayList<>(len); for (Iterable e : collections) { iterList.add(N.iterate(e)); } return parallelZipIterators(iterList, zipFunction, bufferSize); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param collections * @param valuesForNone * @param zipFunction * @return */ @Beta public static Stream parallelZipIterables(final Collection> collections, final List valuesForNone, Function, ? extends R> zipFunction) { return parallelZipIterables(collections, valuesForNone, zipFunction, DEFAULT_BUFFERED_SIZE_PER_ITERATOR); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param collections * @param valuesForNone * @param zipFunction * @param bufferSize * @return */ @Beta public static Stream parallelZipIterables(final Collection> collections, final List valuesForNone, Function, ? extends R> zipFunction, final int bufferSize) { if (N.isNullOrEmpty(collections)) { return Stream.empty(); } final int len = collections.size(); if (len != valuesForNone.size()) { throw new IllegalArgumentException("The size of 'valuesForNone' must be same as the size of the collection of iterators"); } final List> iterList = new ArrayList<>(len); for (Iterable e : collections) { iterList.add(N.iterate(e)); } return parallelZipIterators(iterList, valuesForNone, zipFunction, bufferSize); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param iterators * @param zipFunction * @return * @see #parallelZipIterators(Collection, Function, int, int) */ public static Stream parallelZipIterators(final Collection> iterators, final Function, ? extends R> zipFunction) { return parallelZipIterators(iterators, zipFunction, DEFAULT_BUFFERED_SIZE_PER_ITERATOR); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param iterators * @param zipFunction * @param bufferSize * @return * @see #parallelZipIterators(Collection, Function, int, int) */ public static Stream parallelZipIterators(final Collection> iterators, final Function, ? extends R> zipFunction, final int bufferSize) { return parallelZipIterators(iterators, zipFunction, bufferSize, 0); } /** * * @param * @param * @param iterators * @param zipFunction * @param bufferSize * @param maxThreadNumForZipFunction * @return */ public static Stream parallelZipIterators(final Collection> iterators, final Function, ? extends R> zipFunction, final int bufferSize, final int maxThreadNumForZipFunction) { if (N.isNullOrEmpty(iterators)) { return Stream.empty(); } final Supplier> supplier = () -> { final int len = iterators.size(); final Holder eHolder = new Holder<>(); final MutableBoolean onGoing = MutableBoolean.of(true); final AtomicInteger[] counters = new AtomicInteger[len]; final BlockingQueue[] queues = new ArrayBlockingQueue[len]; final Holder holderForAsyncExecutorUsed = new Holder<>(); boolean noException = false; try { readToQueue(iterators, bufferSize, DEFAULT_ASYNC_EXECUTOR, counters, queues, eHolder, onGoing, holderForAsyncExecutorUsed); noException = true; } finally { if (!noException) { onGoing.setFalse(); } } if (eHolder.value() != null) { setStopFlagAndThrowException(eHolder, onGoing); } final Deque closeHandlers = new LocalArrayDeque<>(1); closeHandlers.add(() -> { onGoing.setFalse(); if (holderForAsyncExecutorUsed.isNotNull()) { shutdownTempExecutor(holderForAsyncExecutorUsed.value()); } }); final IntFunction> iterCreator = taskIdx -> new ObjIteratorEx<>() { Object[] next = null; @Override public boolean hasNext() { if (next == null) { next = new Object[len]; for (int i = 0; i < len; i++) { try { while (next[i] == null && onGoing.value() && (counters[i].get() > 0 || queues[i].size() > 0)) { // (counters[i].get() > 0 || queues[i].size() > 0) is wrong. has to check counter first next[i] = queues[i].poll(MAX_WAIT_TIME_FOR_QUEUE_POLL, TimeUnit.MILLISECONDS); } if (next[i] == null) { onGoing.setFalse(); return false; } } catch (Exception e) { setError(eHolder, e, onGoing); } if (eHolder.value() != null) { setStopFlagAndThrowException(eHolder, onGoing); } } } else { for (int i = 0; i < len; i++) { if (next[i] == null) { return false; } } } return true; } @Override public R next() { if (!hasNext()) { throw new NoSuchElementException(); } for (int i = 0; i < len; i++) { if (next[i] == NONE) { next[i] = null; } } R result = null; try { result = zipFunction.apply(Arrays.asList((T[]) next)); next = null; } catch (Exception e) { setError(eHolder, e, onGoing); } if (eHolder.value() != null) { setStopFlagAndThrowException(eHolder, onGoing); } return result; } }; final int maxThreadNum = checkMaxThreadNum(maxThreadNumForZipFunction, 0, DEFAULT_ASYNC_EXECUTOR); if (maxThreadNum <= 1) { final Iterator iter = iterCreator.apply(0); return new IteratorStream<>(iter, false, null, closeHandlers); } else { final List> iters = new ArrayList<>(maxThreadNum); for (int i = 0; i < maxThreadNum; i++) { iters.add(iterCreator.apply(i)); } return new IteratorStream<>(parallelConcatIterators(iters, iters.size(), 0, false, DEFAULT_ASYNC_EXECUTOR), false, null, closeHandlers); } }; return just(supplier).flatMap(Supplier::get); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param iterators * @param valuesForNone * @param zipFunction * @return * @see #parallelZipIterators(Collection, List, Function, int, int) */ public static Stream parallelZipIterators(final Collection> iterators, final List valuesForNone, Function, ? extends R> zipFunction) { return parallelZipIterators(iterators, valuesForNone, zipFunction, DEFAULT_BUFFERED_SIZE_PER_ITERATOR); } /** * A new thread will be started for each {@code Iterator/Collection/Stream} to read the elements to queue for the {@code zipFunction}. * But the {@code zipFunction} will be executed in a single thread, not multiple threads. * To parallelize the {@code zipFunction}, call {@code Stream.parallelZip(..., bufferSize, maxThreadNumForZipFunction)} or {@code Stream.parallelZip(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param iterators * @param valuesForNone * @param zipFunction * @param bufferSize * @return * @see #parallelZipIterators(Collection, List, Function, int, int) */ public static Stream parallelZipIterators(final Collection> iterators, final List valuesForNone, final Function, ? extends R> zipFunction, final int bufferSize) { return parallelZipIterators(iterators, valuesForNone, zipFunction, bufferSize, 0); } /** * * @param * @param * @param iterators * @param valuesForNone * @param zipFunction * @param bufferSize * @param maxThreadNumForZipFunction * @return */ public static Stream parallelZipIterators(final Collection> iterators, final List valuesForNone, final Function, ? extends R> zipFunction, final int bufferSize, final int maxThreadNumForZipFunction) { if (N.isNullOrEmpty(iterators)) { return Stream.empty(); } if (iterators.size() != valuesForNone.size()) { throw new IllegalArgumentException("The size of 'valuesForNone' must be same as the size of the collection of iterators"); } final Supplier> supplier = () -> { final int len = iterators.size(); final Holder eHolder = new Holder<>(); final MutableBoolean onGoing = MutableBoolean.of(true); final AtomicInteger[] counters = new AtomicInteger[len]; final BlockingQueue[] queues = new ArrayBlockingQueue[len]; final Holder holderForAsyncExecutorUsed = new Holder<>(); boolean noException = false; try { readToQueue(iterators, bufferSize, DEFAULT_ASYNC_EXECUTOR, counters, queues, eHolder, onGoing, holderForAsyncExecutorUsed); noException = true; } finally { if (!noException) { onGoing.setFalse(); } } if (eHolder.value() != null) { setStopFlagAndThrowException(eHolder, onGoing); } final Deque closeHandlers = new LocalArrayDeque<>(1); closeHandlers.add(() -> { onGoing.setFalse(); if (holderForAsyncExecutorUsed.isNotNull()) { shutdownTempExecutor(holderForAsyncExecutorUsed.value()); } }); final IntFunction> iterCreator = taskIdx -> new ObjIteratorEx<>() { Object[] next = null; @Override public boolean hasNext() { if (next == null) { next = new Object[len]; for (int i = 0; i < len; i++) { try { while (next[i] == null && onGoing.value() && (counters[i].get() > 0 || queues[i].size() > 0)) { // (counters[i].get() > 0 || queues[i].size() > 0) is wrong. has to check counter first next[i] = queues[i].poll(MAX_WAIT_TIME_FOR_QUEUE_POLL, TimeUnit.MILLISECONDS); } } catch (Exception e) { setError(eHolder, e, onGoing); } if (eHolder.value() != null) { setStopFlagAndThrowException(eHolder, onGoing); } } } for (int i = 0; i < len; i++) { if (next[i] != null) { return true; } } onGoing.setFalse(); return false; } @Override public R next() { if (!hasNext()) { throw new NoSuchElementException(); } for (int i = 0; i < len; i++) { next[i] = next[i] == NONE ? null : (next[i] == null ? valuesForNone.get(i) : next[i]); } R result = null; try { result = zipFunction.apply(Arrays.asList((T[]) next)); next = null; } catch (Exception e) { setError(eHolder, e, onGoing); } if (eHolder.value() != null) { setStopFlagAndThrowException(eHolder, onGoing); } return result; } }; final int maxThreadNum = checkMaxThreadNum(maxThreadNumForZipFunction, 0, DEFAULT_ASYNC_EXECUTOR); if (maxThreadNum <= 1) { final Iterator iter = iterCreator.apply(0); return new IteratorStream<>(iter, false, null, closeHandlers); } else { final List> iters = new ArrayList<>(maxThreadNum); for (int i = 0; i < maxThreadNum; i++) { iters.add(iterCreator.apply(i)); } return new IteratorStream<>(parallelConcatIterators(iters, iters.size(), 0, false, DEFAULT_ASYNC_EXECUTOR), false, null, closeHandlers); } }; return just(supplier).flatMap(Supplier::get); } // /** // * // * @param c // * @param unzip the second parameter is an output parameter. // * @return // */ // public static Pair, Stream> unzip(final Collection c, final BiConsumer> unzip) { // final Pair, List> p = Iterables.unzip(c, unzip); // // return Pair.of(Stream.of(p.left), Stream.of(p.right)); // } // // /** // * // * @param iter // * @param unzip the second parameter is an output parameter. // * @return // */ // public static Pair, Stream> unzip(final Iterator iter, final BiConsumer> unzip) { // final Pair, List> p = Iterators.unzip(iter, unzip); // // return Pair.of(Stream.of(p.left), Stream.of(p.right)); // } // // /** // * // * @param c // * @param unzip the second parameter is an output parameter. // * @return // */ // public static Triple, Stream, Stream> unzipp(final Collection c, // final BiConsumer> unzip) { // final Triple, List, List> p = Iterables.unzipp(c, unzip); // // return Triple.of(Stream.of(p.left), Stream.of(p.middle), Stream.of(p.right)); // } // // /** // * // * @param iter // * @param unzip the second parameter is an output parameter. // * @return // */ // public static Triple, Stream, Stream> unzipp(final Iterator iter, // final BiConsumer> unzip) { // final Triple, List, List> p = Iterators.unzipp(iter, unzip); // // return Triple.of(Stream.of(p.left), Stream.of(p.middle), Stream.of(p.right)); // } /** * * * @param * @param a * @param b * @param nextSelector first parameter is selected if Nth.FIRST is returned, otherwise the second parameter is selected. * @return */ public static Stream merge(final T[] a, final T[] b, final BiFunction nextSelector) { if (N.isNullOrEmpty(a)) { return of(b); } else if (N.isNullOrEmpty(b)) { return of(a); } return new IteratorStream<>(new ObjIteratorEx() { private final int lenA = a.length; private final int lenB = b.length; private int cursorA = 0; private int cursorB = 0; @Override public boolean hasNext() { return cursorA < lenA || cursorB < lenB; } @Override public T next() { if (cursorA < lenA) { if (cursorB < lenB) { if (nextSelector.apply(a[cursorA], b[cursorB]) == MergeResult.TAKE_FIRST) { return a[cursorA++]; } else { return b[cursorB++]; } } else { return a[cursorA++]; } } else if (cursorB < lenB) { return b[cursorB++]; } else { throw new NoSuchElementException(); } } }); } /** * * * @param * @param a * @param b * @param c * @param nextSelector first parameter is selected if Nth.FIRST is returned, otherwise the second parameter is selected. * @return */ public static Stream merge(final T[] a, final T[] b, final T[] c, final BiFunction nextSelector) { return merge(merge(a, b, nextSelector).iteratorEx(), N.iterate(c), nextSelector); } /** * * * @param * @param a * @param b * @param nextSelector first parameter is selected if Nth.FIRST is returned, otherwise the second parameter is selected. * @return */ public static Stream merge(final Iterable a, final Iterable b, final BiFunction nextSelector) { return merge(N.iterate(a), N.iterate(b), nextSelector); } /** * * * @param * @param a * @param b * @param c * @param nextSelector first parameter is selected if Nth.FIRST is returned, otherwise the second parameter is selected. * @return */ public static Stream merge(final Iterable a, final Iterable b, final Iterable c, final BiFunction nextSelector) { return merge(N.iterate(a), N.iterate(b), N.iterate(c), nextSelector); } /** * * * @param * @param a * @param b * @param nextSelector first parameter is selected if Nth.FIRST is returned, otherwise the second parameter is selected. * @return */ public static Stream merge(final Iterator a, final Iterator b, final BiFunction nextSelector) { return new IteratorStream<>(new ObjIteratorEx() { private final Iterator iterA = a == null ? ObjIterator. empty() : (Iterator) a; private final Iterator iterB = b == null ? ObjIterator. empty() : (Iterator) b; private T nextA = null; private T nextB = null; private boolean hasNextA = false; private boolean hasNextB = false; @Override public boolean hasNext() { return hasNextA || hasNextB || iterA.hasNext() || iterB.hasNext(); } @Override public T next() { if (hasNextA) { if (iterB.hasNext()) { if (nextSelector.apply(nextA, (nextB = iterB.next())) == MergeResult.TAKE_FIRST) { hasNextA = false; hasNextB = true; return nextA; } else { return nextB; } } else { hasNextA = false; return nextA; } } else if (hasNextB) { if (iterA.hasNext()) { if (nextSelector.apply((nextA = iterA.next()), nextB) == MergeResult.TAKE_FIRST) { return nextA; } else { hasNextA = true; hasNextB = false; return nextB; } } else { hasNextB = false; return nextB; } } else if (iterA.hasNext()) { if (iterB.hasNext()) { if (nextSelector.apply((nextA = iterA.next()), (nextB = iterB.next())) == MergeResult.TAKE_FIRST) { hasNextB = true; return nextA; } else { hasNextA = true; return nextB; } } else { return iterA.next(); } } else if (iterB.hasNext()) { return iterB.next(); } else { throw new NoSuchElementException(); } } }); } /** * * * @param * @param a * @param b * @param c * @param nextSelector first parameter is selected if Nth.FIRST is returned, otherwise the second parameter is selected. * @return */ public static Stream merge(final Iterator a, final Iterator b, final Iterator c, final BiFunction nextSelector) { return merge(merge(a, b, nextSelector).iteratorEx(), c, nextSelector); } /** * * * @param * @param a * @param b * @param nextSelector first parameter is selected if Nth.FIRST is returned, otherwise the second parameter is selected. * @return */ public static Stream merge(final Stream a, final Stream b, final BiFunction nextSelector) { return merge(iterate(a), iterate(b), nextSelector).onClose(newCloseHandler(a, b)); } /** * * * @param * @param a * @param b * @param c * @param nextSelector * @return */ public static Stream merge(final Stream a, final Stream b, final Stream c, final BiFunction nextSelector) { return merge(merge(a, b, nextSelector), c, nextSelector); } /** * * * @param * @param c * @param nextSelector first parameter is selected if Nth.FIRST is returned, otherwise the second parameter is selected. * @return */ public static Stream merge(final Collection> c, final BiFunction nextSelector) { N.checkArgNotNull(nextSelector); if (N.isNullOrEmpty(c)) { return empty(); } else if (c.size() == 1) { return (Stream) c.iterator().next(); } else if (c.size() == 2) { final Iterator> iter = c.iterator(); return merge(iter.next(), iter.next(), nextSelector); } final Iterator> iter = c.iterator(); Stream result = merge(iter.next(), iter.next(), nextSelector); while (iter.hasNext()) { result = merge(result, iter.next(), nextSelector); } return result; } /** * * @param * @param collections * @param nextSelector first parameter is selected if Nth.FIRST is returned, otherwise the second parameter is selected. * @return */ public static Stream mergeIterables(final Collection> collections, final BiFunction nextSelector) { N.checkArgNotNull(nextSelector); if (N.isNullOrEmpty(collections)) { return empty(); } else if (collections.size() == 1) { return of(collections.iterator().next()); } else if (collections.size() == 2) { final Iterator> iter = collections.iterator(); return merge(iter.next(), iter.next(), nextSelector); } final List> iterList = new ArrayList<>(collections.size()); for (Iterable e : collections) { iterList.add(N.iterate(e)); } return mergeIterators(iterList, nextSelector); } /** * * @param * @param iterators * @param nextSelector first parameter is selected if Nth.FIRST is returned, otherwise the second parameter is selected. * @return */ public static Stream mergeIterators(final Collection> iterators, final BiFunction nextSelector) { N.checkArgNotNull(nextSelector); if (N.isNullOrEmpty(iterators)) { return empty(); } else if (iterators.size() == 1) { return of(iterators.iterator().next()); } else if (iterators.size() == 2) { final Iterator> iter = iterators.iterator(); return merge(iter.next(), iter.next(), nextSelector); } final Iterator> iter = iterators.iterator(); Stream result = merge(iter.next(), iter.next(), nextSelector); while (iter.hasNext()) { result = merge(result.iteratorEx(), iter.next(), nextSelector); } return result; } /** * All the elements from each input {@code Collection/Iterator/Stream} will be merged into two queues by multiple threads. * Then these two new queues will be merged into one {@code Iterator/Stream} by one thread. * So it's not totally lazy evaluation and may cause out of memory error if there are too many elements merged into the new queues. * Consider using {@code merge}, which is totally lazy evaluation. * * @param * @param c * @param nextSelector first parameter is selected if Nth.FIRST is returned, otherwise the second parameter is selected. * @return */ public static Stream parallelMerge(final Collection> c, final BiFunction nextSelector) { return parallelMerge(c, nextSelector, DEFAULT_MAX_THREAD_NUM); } /** * All the elements from each input {@code Collection/Iterator/Stream} will be merged into two queues by multiple threads. * Then these two new queues will be merged into one {@code Iterator/Stream} by one thread. * So it's not totally lazy evaluation and may cause out of memory error if there are too many elements merged into the new queues. * Consider using {@code merge}, which is totally lazy evaluation. * * @param * @param c * @param nextSelector first parameter is selected if Nth.FIRST is returned, otherwise the second parameter is selected. * @param maxThreadNum * @return */ public static Stream parallelMerge(final Collection> c, final BiFunction nextSelector, final int maxThreadNum) { N.checkArgument(maxThreadNum > 0, "'maxThreadNum' must not less than 1"); if (maxThreadNum <= 1) { return merge(c, nextSelector); } else if (N.isNullOrEmpty(c)) { return empty(); } else if (c.size() == 1) { return (Stream) c.iterator().next(); } final Supplier> supplier = () -> { if (c.size() == 2) { final Iterator> iter1 = c.iterator(); return merge(iter1.next().buffered(), iter1.next().buffered(), nextSelector); } else if (c.size() == 3) { final Iterator> iter2 = c.iterator(); return merge(iter2.next().buffered(), iter2.next().buffered(), iter2.next().buffered(), nextSelector); } final Queue> queue = N.newLinkedList(); for (Stream e : c) { queue.add((Stream) e); } final Holder eHolder = new Holder<>(); final MutableInt cnt = MutableInt.of(c.size()); final List> futureList = new ArrayList<>(c.size() - 1); final int threadNum = N.min(maxThreadNum, c.size() / 2 + 1); AsyncExecutor asyncExecutorToUse = checkAsyncExecutor(DEFAULT_ASYNC_EXECUTOR, threadNum, 0); // TODO Warning: Dead lock could happen if the total thread number started by this stream and its upstream is bigger than StreamBase.CORE_THREAD_POOL_SIZE(1024). // If the total thread number started by this stream and its down stream is big, please specified its owner {@code Executor} by {@code parallel(..., Executor)}. // UPDATE: this dead lock problem has been resolved by using BaseStream.execute(...) for (int i = 0; i < threadNum; i++) { asyncExecutorToUse = execute(asyncExecutorToUse, threadNum, 0, i, futureList, () -> { Stream a = null; Stream b = null; Stream c1 = null; try { while (eHolder.value() == null) { synchronized (queue) { if (cnt.intValue() > 2 && queue.size() > 1) { a = queue.poll(); b = queue.poll(); cnt.decrement(); } else { break; } } c1 = Stream.of((T[]) merge(a, b, nextSelector).toArray()); synchronized (queue) { queue.offer(c1); } } } catch (Throwable e) { setError(eHolder, e); } }); } completeAndShutdownTempExecutor(futureList, eHolder, c, asyncExecutorToUse); return merge(queue.poll(), queue.poll(), nextSelector); }; return Stream.just(supplier).flatMap(Supplier::get); } /** * All the elements from each input {@code Collection/Iterator/Stream} will be merged into two queues by multiple threads. * Then these two new queues will be merged into one {@code Iterator/Stream} by one thread. * So it's not totally lazy evaluation and may cause out of memory error if there are too many elements merged into the new queues. * Consider using {@code merge}, which is totally lazy evaluation. * * @param * @param collections * @param nextSelector * @return */ public static Stream parallelMergeIterables(final Collection> collections, final BiFunction nextSelector) { return parallelMergeIterables(collections, nextSelector, DEFAULT_MAX_THREAD_NUM); } /** * All the elements from each input {@code Collection/Iterator/Stream} will be merged into two queues by multiple threads. * Then these two new queues will be merged into one {@code Iterator/Stream} by one thread. * So it's not totally lazy evaluation and may cause out of memory error if there are too many elements merged into the new queues. * Consider using {@code merge}, which is totally lazy evaluation. * * @param * @param collections * @param nextSelector * @param maxThreadNum * @return */ public static Stream parallelMergeIterables(final Collection> collections, final BiFunction nextSelector, final int maxThreadNum) { N.checkArgNotNull(nextSelector); if (maxThreadNum <= 1) { return mergeIterables(collections, nextSelector); } else if (N.isNullOrEmpty(collections)) { return empty(); } else if (collections.size() == 1) { return of(collections.iterator().next()); } else if (collections.size() == 2) { final Iterator> iter = collections.iterator(); return merge(iter.next(), iter.next(), nextSelector); } else if (collections.size() == 3) { final Iterator> iter = collections.iterator(); return merge(iter.next(), iter.next(), iter.next(), nextSelector); } final List> iterList = new ArrayList<>(collections.size()); for (Iterable e : collections) { iterList.add(N.iterate(e)); } return parallelMergeIterators(iterList, nextSelector, maxThreadNum); } /** * All the elements from each input {@code Collection/Iterator/Stream} will be merged into two queues by multiple threads. * Then these two new queues will be merged into one {@code Iterator/Stream} by one thread. * So it's not totally lazy evaluation and may cause out of memory error if there are too many elements merged into the new queues. * Consider using {@code merge}, which is totally lazy evaluation. * * @param * @param iterators * @param nextSelector first parameter is selected if Nth.FIRST is returned, otherwise the second parameter is selected. * @return */ public static Stream parallelMergeIterators(final Collection> iterators, final BiFunction nextSelector) { return parallelMergeIterators(iterators, nextSelector, DEFAULT_MAX_THREAD_NUM); } /** * All the elements from each input {@code Collection/Iterator/Stream} will be merged into two queues by multiple threads. * Then these two new queues will be merged into one {@code Iterator/Stream} by one thread. * So it's not totally lazy evaluation and may cause out of memory error if there are too many elements merged into the new queues. * Consider using {@code merge}, which is totally lazy evaluation. * * @param * @param iterators * @param nextSelector first parameter is selected if Nth.FIRST is returned, otherwise the second parameter is selected. * @param maxThreadNum * @return */ public static Stream parallelMergeIterators(final Collection> iterators, final BiFunction nextSelector, final int maxThreadNum) { N.checkArgument(maxThreadNum > 0, "'maxThreadNum' must not less than 1"); if (maxThreadNum <= 1) { return mergeIterators(iterators, nextSelector); } else if (N.isNullOrEmpty(iterators)) { return empty(); } else if (iterators.size() == 1) { return of(iterators.iterator().next()); } final Supplier> supplier = () -> { if (iterators.size() == 2) { final Iterator> iter1 = iterators.iterator(); final Iterator a1 = iter1.next(); final Iterator b1 = iter1.next(); return merge(a1 instanceof BufferedIterator ? a1 : Stream.of(a1).buffered().iteratorEx(), b1 instanceof BufferedIterator ? b1 : Stream.of(b1).buffered().iteratorEx(), nextSelector); } else if (iterators.size() == 3) { final Iterator> iter2 = iterators.iterator(); final Iterator iterA = iter2.next(); final Iterator iterB = iter2.next(); final Iterator iterC = iter2.next(); return merge(iterA instanceof BufferedIterator ? iterA : Stream.of(iterA).buffered().iteratorEx(), iterB instanceof BufferedIterator ? iterB : Stream.of(iterB).buffered().iteratorEx(), iterC instanceof BufferedIterator ? iterC : Stream.of(iterC).buffered().iteratorEx(), nextSelector); } final Queue> queue = N.newLinkedList(iterators); final Holder eHolder = new Holder<>(); final MutableInt cnt = MutableInt.of(iterators.size()); final List> futureList = new ArrayList<>(iterators.size() - 1); final int threadNum = N.min(maxThreadNum, iterators.size() / 2 + 1); AsyncExecutor asyncExecutorToUse = checkAsyncExecutor(DEFAULT_ASYNC_EXECUTOR, threadNum, 0); // TODO Warning: Dead lock could happen if the total thread number started by this stream and its upstream is bigger than StreamBase.CORE_THREAD_POOL_SIZE(1024). // If the total thread number started by this stream and its down stream is big, please specified its owner {@code Executor} by {@code parallel(..., Executor)}. // UPDATE: this dead lock problem has been resolved by using BaseStream.execute(...) for (int i = 0; i < threadNum; i++) { asyncExecutorToUse = execute(asyncExecutorToUse, threadNum, 0, i, futureList, () -> { Iterator a = null; Iterator b = null; Iterator c = null; try { while (eHolder.value() == null) { synchronized (queue) { if (cnt.intValue() > 2 && queue.size() > 1) { a = queue.poll(); b = queue.poll(); cnt.decrement(); } else { break; } } c = (Iterator) ObjIteratorEx.of(merge(a instanceof BufferedIterator ? a : Stream.of(a).buffered().iteratorEx(), b instanceof BufferedIterator ? b : Stream.of(b).buffered().iteratorEx(), nextSelector).toArray()); synchronized (queue) { queue.offer(c); } } } catch (Throwable e) { setError(eHolder, e); } }); } try { complete(futureList, eHolder); } finally { shutdownTempExecutor(asyncExecutorToUse); } final Iterator a2 = queue.poll(); final Iterator b2 = queue.poll(); return merge(a2 instanceof BufferedIterator ? a2 : Stream.of(a2).buffered().iteratorEx(), b2 instanceof BufferedIterator ? b2 : Stream.of(b2).buffered().iteratorEx(), nextSelector); }; return Stream.just(supplier).flatMap(Supplier::get); } private static void readToQueue(final Iterator a, final Iterator b, final AsyncExecutor asyncExecutor, final AtomicInteger threadCounterA, final AtomicInteger threadCounterB, final BlockingQueue queueA, final BlockingQueue queueB, final Holder eHolder, final MutableBoolean onGoing, final Holder holderForAsyncExecutorUsed) { AsyncExecutor asyncExecutorToUse = checkAsyncExecutor(asyncExecutor, 2, 0); final Iterator iterA = a == null ? ObjIterator. empty() : (Iterator) a; final Iterator iterB = b == null ? ObjIterator. empty() : (Iterator) b; asyncExecutorToUse = execute(asyncExecutorToUse, 2, 0, 0, () -> { try { A nextA = null; while (onGoing.value() && iterA.hasNext()) { nextA = iterA.next(); if (nextA == null) { nextA = (A) NONE; } while (onGoing.value() && !queueA.offer(nextA, MAX_WAIT_TIME_FOR_QUEUE_OFFER, TimeUnit.MILLISECONDS)) { // continue } } } catch (Exception e) { setError(eHolder, e, onGoing); } finally { threadCounterA.decrementAndGet(); } }); asyncExecutorToUse = execute(asyncExecutorToUse, 2, 0, 1, () -> { try { B nextB = null; while (onGoing.value() && iterB.hasNext()) { nextB = iterB.next(); if (nextB == null) { nextB = (B) NONE; } while (onGoing.value() && !queueB.offer(nextB, MAX_WAIT_TIME_FOR_QUEUE_OFFER, TimeUnit.MILLISECONDS)) { // continue } } } catch (Exception e) { setError(eHolder, e, onGoing); } finally { threadCounterB.decrementAndGet(); } }); holderForAsyncExecutorUsed.setValue(asyncExecutorToUse); } private static void readToQueue(final Iterator a, final Iterator b, final Iterator c, final AsyncExecutor asyncExecutor, final AtomicInteger threadCounterA, final AtomicInteger threadCounterB, final AtomicInteger threadCounterC, final BlockingQueue queueA, final BlockingQueue queueB, final BlockingQueue queueC, final Holder eHolder, final MutableBoolean onGoing, final Holder holderForAsyncExecutorUsed) { AsyncExecutor asyncExecutorToUse = checkAsyncExecutor(asyncExecutor, 3, 0); final Iterator iterA = a == null ? ObjIterator. empty() : (Iterator) a; final Iterator iterB = b == null ? ObjIterator. empty() : (Iterator) b; final Iterator iterC = c == null ? ObjIterator. empty() : (Iterator) c; asyncExecutorToUse = execute(asyncExecutorToUse, 3, 0, 0, () -> { try { A nextA = null; while (onGoing.value() && iterA.hasNext()) { nextA = iterA.next(); if (nextA == null) { nextA = (A) NONE; } while (onGoing.value() && !queueA.offer(nextA, MAX_WAIT_TIME_FOR_QUEUE_OFFER, TimeUnit.MILLISECONDS)) { // continue } } } catch (Exception e) { setError(eHolder, e, onGoing); } finally { threadCounterA.decrementAndGet(); } }); asyncExecutorToUse = execute(asyncExecutorToUse, 3, 0, 1, () -> { try { B nextB = null; while (onGoing.value() && iterB.hasNext()) { nextB = iterB.next(); if (nextB == null) { nextB = (B) NONE; } while (onGoing.value() && !queueB.offer(nextB, MAX_WAIT_TIME_FOR_QUEUE_OFFER, TimeUnit.MILLISECONDS)) { // continue } } } catch (Exception e) { setError(eHolder, e, onGoing); } finally { threadCounterB.decrementAndGet(); } }); asyncExecutorToUse = execute(asyncExecutorToUse, 3, 0, 2, () -> { try { C nextC = null; while (onGoing.value() && iterC.hasNext()) { nextC = iterC.next(); if (nextC == null) { nextC = (C) NONE; } while (onGoing.value() && !queueC.offer(nextC, MAX_WAIT_TIME_FOR_QUEUE_OFFER, TimeUnit.MILLISECONDS)) { // continue } } } catch (Exception e) { setError(eHolder, e, onGoing); } finally { threadCounterC.decrementAndGet(); } }); holderForAsyncExecutorUsed.setValue(asyncExecutorToUse); } private static void readToQueue(final Collection> c, final int bufferSize, final AsyncExecutor asyncExecutor, final AtomicInteger[] counters, final BlockingQueue[] queues, final Holder eHolder, final MutableBoolean onGoing, final Holder holderForAsyncExecutorUsed) { final int threadNum = c.size(); AsyncExecutor asyncExecutorToUse = checkAsyncExecutor(asyncExecutor, threadNum, 0); int idx = 0; for (Iterator e : c) { counters[idx] = new AtomicInteger(1); queues[idx] = new ArrayBlockingQueue<>(bufferSize); final Iterator iter = e; final AtomicInteger count = counters[idx]; final BlockingQueue queue = queues[idx]; asyncExecutorToUse = execute(asyncExecutorToUse, threadNum, 0, idx, () -> { try { Object next = null; while (onGoing.value() && iter.hasNext()) { next = iter.next(); if (next == null) { next = NONE; } while (onGoing.value() && !queue.offer(next, MAX_WAIT_TIME_FOR_QUEUE_OFFER, TimeUnit.MILLISECONDS)) { // continue } } } catch (Exception e1) { setError(eHolder, e1, onGoing); } finally { count.decrementAndGet(); } }); idx++; } holderForAsyncExecutorUsed.setValue(asyncExecutorToUse); } public abstract static class StreamEx extends Stream { private StreamEx(boolean sorted, Comparator cmp, Collection closeHandlers) { //NOSONAR super(sorted, cmp, closeHandlers); // Factory class. } } }