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.3.16
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.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 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.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.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.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.ShortIterator;
import com.landawn.abacus.util.Splitter;
import com.landawn.abacus.util.Throwables;
import com.landawn.abacus.util.u.Holder;
import com.landawn.abacus.util.u.Optional;
import com.landawn.abacus.util.u.OptionalDouble;
import com.landawn.abacus.util.u.OptionalInt;
import com.landawn.abacus.util.u.OptionalLong;
import com.landawn.abacus.util.function.BiConsumer;
import com.landawn.abacus.util.function.BiFunction;
import com.landawn.abacus.util.function.BiPredicate;
import com.landawn.abacus.util.function.BinaryOperator;
import com.landawn.abacus.util.function.BooleanSupplier;
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.Consumer;
import com.landawn.abacus.util.function.DoubleBiFunction;
import com.landawn.abacus.util.function.DoubleConsumer;
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.Function;
import com.landawn.abacus.util.function.IntBiFunction;
import com.landawn.abacus.util.function.IntConsumer;
import com.landawn.abacus.util.function.IntFunction;
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.LongConsumer;
import com.landawn.abacus.util.function.LongFunction;
import com.landawn.abacus.util.function.LongNFunction;
import com.landawn.abacus.util.function.LongSupplier;
import com.landawn.abacus.util.function.LongTriFunction;
import com.landawn.abacus.util.function.Predicate;
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.Supplier;
import com.landawn.abacus.util.function.ToByteFunction;
import com.landawn.abacus.util.function.ToCharFunction;
import com.landawn.abacus.util.function.ToDoubleFunction;
import com.landawn.abacus.util.function.ToFloatFunction;
import com.landawn.abacus.util.function.ToIntFunction;
import com.landawn.abacus.util.function.ToLongFunction;
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.function.UnaryOperator;
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 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(Class targetType) { if (isParallel()) { return (Stream) sequential().filter(Fn.instanceOf(targetType)).parallel(maxThreadNum(), 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)); } @ParallelSupported @IntermediateOp public abstract Stream map(Function mapper); @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); @ParallelSupported @IntermediateOp public abstract Stream slidingMap(BiFunction mapper); /** * Slide with windowSize = 2 and the specified increment, then map by the specified mapper. * * @param mapper * @param increment * @return */ @ParallelSupported @IntermediateOp public abstract Stream slidingMap(BiFunction mapper, int increment); @ParallelSupported @IntermediateOp public abstract Stream slidingMap(BiFunction mapper, int increment, boolean ignoreNotPaired); @ParallelSupported @IntermediateOp public abstract Stream slidingMap(TriFunction mapper); /** * Slide with windowSize = 3 and the specified increment, then map by the specified mapper. * * @param mapper * @param increment * @return */ @ParallelSupported @IntermediateOp public abstract Stream slidingMap(TriFunction mapper, int increment); @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); @SequentialOnly @IntermediateOp public abstract Stream mapFirst(Function mapperForFirst); @ParallelSupported @IntermediateOp public abstract Stream mapFirstOrElse(Function mapperForFirst, Function mapperForElse); @SequentialOnly @IntermediateOp public abstract Stream mapLast(Function mapperForLast); @ParallelSupported @IntermediateOp public abstract Stream mapLastOrElse(Function mapperForLast, Function mapperForElse); @ParallelSupported @IntermediateOp public abstract CharStream mapToChar(ToCharFunction mapper); @ParallelSupported @IntermediateOp public abstract ByteStream mapToByte(ToByteFunction mapper); @ParallelSupported @IntermediateOp public abstract ShortStream mapToShort(ToShortFunction mapper); @ParallelSupported @IntermediateOp public abstract IntStream mapToInt(ToIntFunction mapper); @ParallelSupported @IntermediateOp public abstract LongStream mapToLong(ToLongFunction mapper); @ParallelSupported @IntermediateOp public abstract FloatStream mapToFloat(ToFloatFunction mapper); @ParallelSupported @IntermediateOp public abstract DoubleStream mapToDouble(ToDoubleFunction mapper); // public abstract EntryStream mapToEntry(); @ParallelSupported @IntermediateOp public abstract EntryStream mapToEntry(Function> mapper); @ParallelSupported @IntermediateOp public abstract EntryStream mapToEntry(Function keyMapper, Function valueMapper); // public abstract Stream mapp(Function> mapper); @ParallelSupported @IntermediateOp public abstract Stream flatMap(Function> mapper); @ParallelSupported @IntermediateOp public abstract Stream flattMap(Function> mapper); @ParallelSupported @IntermediateOp public abstract Stream flatMapp(Function mapper); @ParallelSupported @IntermediateOp public abstract CharStream flatMapToChar(Function mapper); @ParallelSupported @IntermediateOp public abstract CharStream flattMapToChar(Function mapper); @ParallelSupported @IntermediateOp public abstract ByteStream flatMapToByte(Function mapper); @ParallelSupported @IntermediateOp public abstract ByteStream flattMapToByte(Function mapper); @ParallelSupported @IntermediateOp public abstract ShortStream flatMapToShort(Function mapper); @ParallelSupported @IntermediateOp public abstract ShortStream flattMapToShort(Function mapper); @ParallelSupported @IntermediateOp public abstract IntStream flatMapToInt(Function mapper); @ParallelSupported @IntermediateOp public abstract IntStream flattMapToInt(Function mapper); @ParallelSupported @IntermediateOp public abstract LongStream flatMapToLong(Function mapper); @ParallelSupported @IntermediateOp public abstract LongStream flattMapToLong(Function mapper); @ParallelSupported @IntermediateOp public abstract FloatStream flatMapToFloat(Function mapper); @ParallelSupported @IntermediateOp public abstract FloatStream flattMapToFloat(Function mapper); @ParallelSupported @IntermediateOp public abstract DoubleStream flatMapToDouble(Function mapper); @ParallelSupported @IntermediateOp public abstract DoubleStream flattMapToDouble(Function mapper); @ParallelSupported @IntermediateOp public abstract EntryStream flatMapToEntry(Function>> mapper); @ParallelSupported @IntermediateOp public abstract EntryStream flattMapToEntry(Function> mapper); @ParallelSupported @IntermediateOp public abstract EntryStream flatMappToEntry(Function> mapper); /** * @implNote same as ====> *

     * skipNull().flattMap(mapper)
     * 
* * @param * @param mapper * @return */ @Beta @ParallelSupported @IntermediateOp public Stream flattMapIfNotNull(Function> mapper) { return skipNull().flattMap(mapper); } /** * @implNote same as ====> *
     * skipNull().flattMap(mapper).skipNull().flattMap(mapper2)
     * 
* * @param * @param * @param mapper * @param mapper2 * @return */ @Beta @ParallelSupported @IntermediateOp public Stream flattMapIfNotNull(Function> mapper, Function> mapper2) { return skipNull().flattMap(mapper).skipNull().flattMap(mapper2); } @Beta @ParallelSupported @IntermediateOp public abstract Stream mapMulti(BiConsumer> mapper); @Beta @ParallelSupported @IntermediateOp public abstract IntStream mapMultiToInt(BiConsumer mapper); @Beta @ParallelSupported @IntermediateOp public abstract LongStream mapMultiToLong(BiConsumer mapper); @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); @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract Stream>> groupBy(final Function keyMapper); @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract Stream>> groupBy(final Function keyMapper, final Supplier>> mapFactory); /** * * @param keyMapper * @param valueMapper * @return * @see Collectors#toMultimap(Function, Function) */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract Stream>> groupBy(Function keyMapper, Function valueMapper); /** * * @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); @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract Stream> groupBy(final Function keyMapper, final Collector downstream); @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract Stream> groupBy(final Function keyMapper, final Collector downstream, final Supplier> mapFactory); @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); @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract Stream> groupBy(final Function keyMapper, final Function valueMapper, BinaryOperator mergeFunction); @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); @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract EntryStream> groupByToEntry(final Function keyMapper); @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract EntryStream> groupByToEntry(final Function keyMapper, final Supplier>> mapFactory); /** * * @param keyMapper * @param valueMapper * @return * @see Collectors#toMultimap(Function, Function) */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract EntryStream> groupByToEntry(Function keyMapper, Function valueMapper); /** * * @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); @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract EntryStream groupByToEntry(final Function keyMapper, final Collector downstream); @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract EntryStream groupByToEntry(final Function keyMapper, final Collector downstream, final Supplier> mapFactory); @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract EntryStream groupByToEntry(final Function keyMapper, final Function valueMapper, final Collector downstream); @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract EntryStream groupByToEntry(final Function keyMapper, final Function valueMapper, final Collector downstream, final Supplier> mapFactory); @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract EntryStream groupByToEntry(final Function keyMapper, final Function valueMapper, BinaryOperator mergeFunction); @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 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 predicate * @param downstream * @return * @see Collectors#partitioningBy(Predicate, Collector) */ @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract EntryStream partitionByToEntry(final Predicate predicate, final Collector downstream); @ParallelSupported @IntermediateOp @TerminalOpTriggered public Stream> countBy(final Function keyMapper) { return groupBy(keyMapper, Collectors.countingInt()); } @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 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 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 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 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 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 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); @SequentialOnly @IntermediateOp public abstract Stream> splitToSet(Predicate predicate); @SequentialOnly @IntermediateOp public abstract > Stream split(Predicate predicate, Supplier collectionSupplier); @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); @SequentialOnly @IntermediateOp public abstract > Stream sliding(int windowSize, IntFunction collectionSupplier); @SequentialOnly @IntermediateOp public abstract > Stream sliding(int windowSize, int increment, IntFunction collectionSupplier); @SequentialOnly @IntermediateOp public abstract Stream sliding(int windowSize, Collector collector); @SequentialOnly @IntermediateOp public abstract Stream sliding(int windowSize, int increment, Collector collector); /** * Split this stream by the specified duration. * * @param duration * @return * @see Fn#window(Duration, LongSupplier) */ @Beta @SequentialOnly @IntermediateOp public abstract Stream> window(Duration duration); /** * * @param duration * @param startTime * @return * @see #window(Duration) * @see Fn#window(Duration, LongSupplier) * @see #sliding(int, int, Collector) */ @Beta @SequentialOnly @IntermediateOp public abstract Stream> window(Duration duration, LongSupplier startTime); /** * * @param duration * @return * @see #window(Duration) * @see Fn#window(Duration, LongSupplier) * @see #sliding(int, int, Collector) */ @Beta @SequentialOnly @IntermediateOp public abstract Stream> windowToList(Duration duration); /** * * @param duration * @return * @see #window(Duration) * @see Fn#window(Duration, LongSupplier) * @see #sliding(int, int, Collector) */ @SequentialOnly @IntermediateOp public abstract Stream> windowToSet(Duration duration); /** * * @param duration * @param collectionSupplier * @return * @see #window(Duration) * @see Fn#window(Duration, LongSupplier) * @see #sliding(int, int, Collector) */ @Beta @SequentialOnly @IntermediateOp public abstract > Stream window(Duration duration, Supplier collectionSupplier); /** * * @param duration * @param startTime * @param collectionSupplier * @return * @see #window(Duration) * @see Fn#window(Duration, LongSupplier) * @see #sliding(int, int, Collector) */ @Beta @SequentialOnly @IntermediateOp public abstract > Stream window(Duration duration, LongSupplier startTime, Supplier collectionSupplier); /** * * @param duration * @param collector * @return * @see #window(Duration) * @see Fn#window(Duration, LongSupplier) * @see #sliding(int, int, Collector) */ @Beta @SequentialOnly @IntermediateOp public abstract Stream window(Duration duration, Collector collector); /** * * @param duration * @param startTime * @param collector * @return * @see #window(Duration) * @see Fn#window(Duration, LongSupplier) * @see #sliding(int, int, Collector) */ @Beta @SequentialOnly @IntermediateOp public abstract Stream window(Duration duration, LongSupplier startTime, Collector collector); /** * * @param duration * @param incrementInMillis * @return * @see #window(Duration) * @see Fn#window(Duration, LongSupplier) * @see #sliding(int, int, Collector) */ @Beta @SequentialOnly @IntermediateOp public abstract Stream> window(Duration duration, long incrementInMillis); /** * * @param duration * @param incrementInMillis * @param startTime * @return * @see #window(Duration) * @see Fn#window(Duration, LongSupplier) * @see #sliding(int, int, Collector) */ @Beta @SequentialOnly @IntermediateOp public abstract Stream> window(Duration duration, long incrementInMillis, LongSupplier startTime); /** * * @param duration * @param incrementInMillis * @return * @see #window(Duration) * @see Fn#window(Duration, LongSupplier) * @see #sliding(int, int, Collector) */ @Beta @SequentialOnly @IntermediateOp public abstract Stream> windowToList(Duration duration, long incrementInMillis); /** * * @param duration * @param incrementInMillis * @return * @see #window(Duration) * @see Fn#window(Duration, LongSupplier) * @see #sliding(int, int, Collector) */ @Beta @SequentialOnly @IntermediateOp public abstract Stream> windowToSet(Duration duration, long incrementInMillis); /** * * @param duration * @param incrementInMillis * @param collectionSupplier * @return * @see #window(Duration) * @see Fn#window(Duration, LongSupplier) * @see #sliding(int, int, Collector) */ @Beta @SequentialOnly @IntermediateOp public abstract > Stream window(Duration duration, long incrementInMillis, Supplier collectionSupplier); /** * * @param duration * @param incrementInMillis * @param startTime * @param collectionSupplier * @return * @see #window(Duration) * @see Fn#window(Duration, LongSupplier) * @see #sliding(int, int, Collector) */ @Beta @SequentialOnly @IntermediateOp public abstract > Stream window(Duration duration, long incrementInMillis, LongSupplier startTime, Supplier collectionSupplier); /** * * @param duration * @param incrementInMillis * @param collector * @return * @see #window(Duration) * @see Fn#window(Duration, LongSupplier) * @see #sliding(int, int, Collector) */ @Beta @SequentialOnly @IntermediateOp public abstract Stream window(Duration duration, long incrementInMillis, Collector collector); /** * * @param duration * @param incrementInMillis * @param startTime * @param collector * @return * @see #window(Duration) * @see Fn#window(Duration, LongSupplier) * @see #sliding(int, int, Collector) */ @Beta @SequentialOnly @IntermediateOp public abstract Stream window(Duration duration, long incrementInMillis, LongSupplier startTime, Collector collector); /** * * @param maxWindowSize * @param maxDuration * @return * @see #window(int, Duration, LongSupplier, Supplier) * @see Fn#window(int, Duration, LongSupplier, Supplier) */ @Beta @SequentialOnly @IntermediateOp public abstract Stream> window(int maxWindowSize, Duration maxDuration); /** * * @param maxWindowSize * @param maxDuration * @param startTime * @return * @see #window(int, Duration, LongSupplier, Supplier) * @see Fn#window(int, Duration, LongSupplier, Supplier) * @see #sliding(int, int, Collector) */ @Beta @SequentialOnly @IntermediateOp public abstract Stream> window(int maxWindowSize, Duration maxDuration, LongSupplier startTime); /** * * @param maxWindowSize * @param maxDuration * @param collectionSupplier * @return * @see #window(int, Duration, LongSupplier, Supplier) * @see Fn#window(int, Duration, LongSupplier, Supplier) * @see #sliding(int, int, Collector) */ @Beta @SequentialOnly @IntermediateOp public abstract > Stream window(int maxWindowSize, Duration maxDuration, Supplier collectionSupplier); /** * Split this stream at where {@code maxWindowSize} or {@code maxDuration} reaches first. * * @param maxWindowSize * @param maxDuration * @param startTime * @param collectionSupplier * @return * @see #window(int, Duration, LongSupplier, Supplier) * @see Fn#window(int, Duration, LongSupplier, Supplier) * @see #sliding(int, int, Collector) */ @Beta @SequentialOnly @IntermediateOp public abstract > Stream window(int maxWindowSize, Duration maxDuration, LongSupplier startTime, Supplier collectionSupplier); /** * * @param maxWindowSize * @param maxDuration * @param collector * @return * @see #window(int, Duration, LongSupplier, Collector) * @see Fn#window(int, Duration, LongSupplier, Collector) * @see #sliding(int, int, Collector) */ @Beta @SequentialOnly @IntermediateOp public abstract Stream window(int maxWindowSize, Duration maxDuration, Collector collector); /** * Split this stream at where {@code maxWindowSize} or {@code maxDuration} reaches first. * * @param maxWindowSize * @param maxDuration * @param startTime * @param collector * @return * @see #window(Duration, long, LongSupplier, Collector) * @see Fn#window(int, Duration, LongSupplier, Collector) * @see #sliding(int, int, Collector) */ @Beta @SequentialOnly @IntermediateOp public abstract Stream window(int maxWindowSize, Duration maxDuration, LongSupplier startTime, 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. ofLinkedHashMap(); if (isParallel()) { return groupBy(Fn. identity(), Fn. identity(), mergeFunction, supplier) // .sequential() .map(Fn.value()) .parallel(maxThreadNum(), 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 sequential() // .groupBy(Fn. identity(), Collectors.counting(), supplier) .filter(Fn. testByValue(occurrencesFilter)) // .map(Fn. key()) .parallel(maxThreadNum(), splitor(), asyncExecutor(), cancelUncompletedThreads()); } else { return groupBy(Fn. identity(), Collectors.counting(), supplier) // .filter(Fn. testByValue(occurrencesFilter)) .map(Fn. key()); } } /** * 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 filter by occurrences. * * @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> ofLinkedHashMap(); if (isParallel()) { return groupBy(Fn. keyed(keyMapper), Collectors.counting(), supplier) // .sequential() .filter(Fn., Long> testByValue(occurrencesFilter)) .map(Fn. kkv()) .parallel(maxThreadNum(), splitor(), asyncExecutor(), cancelUncompletedThreads()); } else { return groupBy(Fn. keyed(keyMapper), Collectors.counting(), supplier) // .filter(Fn., Long> testByValue(occurrencesFilter)) .map(Fn. kkv()); } } /** * Distinct and merge duplicated elements. * * @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. ofLinkedHashMap(); if (isParallel()) { return groupBy(keyMapper, Fn. identity(), mergeFunction, supplier) // .sequential() .map(Fn.value()) .parallel(maxThreadNum(), splitor(), asyncExecutor(), cancelUncompletedThreads()); } else { return groupBy(keyMapper, Fn. identity(), mergeFunction, supplier).sequential().map(Fn.value()); } } @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract Stream sorted(Comparator comparator); @SuppressWarnings("rawtypes") @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract Stream sortedBy(Function keyMapper); @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract Stream sortedByInt(ToIntFunction keyMapper); @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract Stream sortedByLong(ToLongFunction keyMapper); @ParallelSupported @IntermediateOp @TerminalOpTriggered public abstract Stream sortedByDouble(ToDoubleFunction keyMapper); /** * *
* 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); /** * 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); /** * 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); @SequentialOnly @IntermediateOp public abstract Stream skipNull(); /** * 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(); @ParallelSupported @TerminalOp public abstract void forEach(Throwables.Consumer action) throws E; @ParallelSupported @TerminalOp public abstract void forEachIndexed(Throwables.IndexedConsumer action) throws E; /** * * @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 */ @Beta @ParallelSupported @TerminalOp public abstract void forEachUntil(Throwables.BiConsumer action) throws E; /** * * @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 */ @Beta @ParallelSupported @TerminalOp public abstract void forEachUntil(MutableBoolean flagToBreak, Throwables.Consumer action) throws E; @ParallelSupported @TerminalOp public abstract void forEach(Throwables.Consumer action, Throwables.Runnable onComplete) throws E, E2; @ParallelSupported @TerminalOp public abstract void forEach( final Throwables.Function, E> flatMapper, final Throwables.BiConsumer action) throws E, E2; @ParallelSupported @TerminalOp public abstract void forEach( final Throwables.Function, E> flatMapper, final Throwables.Function, E2> flatMapper2, final Throwables.TriConsumer action) throws E, E2, E3; @ParallelSupported @TerminalOp public abstract void forEachPair(final Throwables.BiConsumer action) throws E; /** * Slide with windowSize = 2 and the specified increment, then consume by the specified mapper. * * @param mapper * @param increment * @return */ @ParallelSupported @TerminalOp public abstract void forEachPair(final Throwables.BiConsumer action, final int increment) throws E; @ParallelSupported @TerminalOp public abstract void forEachTriple(final Throwables.TriConsumer action) throws E; /** * Slide with windowSize = 3 and the specified increment, then consume by the specified mapper. * * @param mapper * @param increment * @return */ @ParallelSupported @TerminalOp public abstract void forEachTriple(final Throwables.TriConsumer action, final int increment) throws E; @ParallelSupported @TerminalOp public abstract boolean anyMatch(Throwables.Predicate predicate) throws E; @ParallelSupported @TerminalOp public abstract boolean allMatch(Throwables.Predicate predicate) throws E; @ParallelSupported @TerminalOp public abstract boolean noneMatch(Throwables.Predicate predicate) throws E; @ParallelSupported @TerminalOp public abstract boolean nMatch(long atLeast, long atMost, Throwables.Predicate predicate) throws E; @ParallelSupported @TerminalOp public abstract Optional findFirst(Throwables.Predicate predicate) throws E; /** * 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; @ParallelSupported @TerminalOp public abstract Optional findAny(Throwables.Predicate predicate) throws E; @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 init * @param predicateForFirst * @param predicateForLast * @return */ @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 preFunc * @param predicateForFirst * @param predicateForLast * @return */ @SequentialOnly @TerminalOp public abstract Optional findFirstOrLast(final Function preFunc, final Throwables.BiPredicate predicateForFirst, final Throwables.BiPredicate predicateForLast) throws E, E2; @SequentialOnly @TerminalOp public abstract boolean containsAll(T... a); @SequentialOnly @TerminalOp public abstract boolean containsAll(Collection c); @SequentialOnly @TerminalOp public abstract boolean containsAny(T... a); @SequentialOnly @TerminalOp public abstract boolean containsAny(Collection c); @SequentialOnly @TerminalOp public abstract
A[] toArray(IntFunction generator); /** * * @param keyMapper * @param valueMapper * @return * @see Collectors#toMap(Function, Function) */ @ParallelSupported @TerminalOp public ImmutableMap toImmutableMap(Throwables.Function keyMapper, Throwables.Function valueMapper) throws E, E2 { return ImmutableMap.of(toMap(keyMapper, valueMapper)); } /** * * @param keyMapper * @param valueMapper * @param mergeFunction * @return * @see Collectors#toMap(Function, Function) */ @ParallelSupported @TerminalOp public ImmutableMap toImmutableMap(Throwables.Function keyMapper, Throwables.Function valueMapper, BinaryOperator mergeFunction) throws E, E2 { return ImmutableMap.of(toMap(keyMapper, valueMapper, mergeFunction)); } /** * * @param keyMapper * @param valueMapper * @return * @see Collectors#toMap(Function, Function) */ @ParallelSupported @TerminalOp public abstract Map toMap(Throwables.Function keyMapper, Throwables.Function valueMapper) throws E, E2; /** * * @param keyMapper * @param valueMapper * @param mergeFunction * @return * @see Collectors#toMap(Function, Function, BinaryOperator) */ @ParallelSupported @TerminalOp public abstract Map toMap(Throwables.Function keyMapper, Throwables.Function valueMapper, BinaryOperator mergeFunction) throws E, E2; /** * * @param keyMapper * @param valueMapper * @param mapFactory * @return * @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 keyMapper * @param valueMapper * @param mergeFunction * @param mapFactory * @return * @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(com.landawn.abacus.util.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(com.landawn.abacus.util.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(com.landawn.abacus.util.Throwables.Function, com.landawn.abacus.util.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(com.landawn.abacus.util.Throwables.Function, com.landawn.abacus.util.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 keyMapper * @return * @see Collectors#groupingBy(Function) */ @ParallelSupported @TerminalOp public abstract Map> groupTo(Throwables.Function keyMapper) throws E; /** * * @param keyMapper * @param mapFactory * @return * @see Collectors#groupingBy(Function, Supplier) */ @ParallelSupported @TerminalOp public abstract >, E extends Exception> M groupTo(Throwables.Function keyMapper, final Supplier mapFactory) throws E; @ParallelSupported @TerminalOp public abstract Map> groupTo(Throwables.Function keyMapper, Throwables.Function valueMapper) throws E, E2; /** * * @param keyMapper * @param valueMapper * @param mapFactory * @return * @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 keyMapper * @param downstream * @return * @see Collectors#groupingBy(Function, Collector) */ @ParallelSupported @TerminalOp public abstract Map groupTo(Throwables.Function keyMapper, final Collector downstream) throws E; /** * * @param keyMapper * @param downstream * @param mapFactory * @return * @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 keyMapper * @param valueMapper * @param downstream * @return * @see Collectors#groupingBy(Function, Collector) */ @ParallelSupported @TerminalOp public abstract Map groupTo(Throwables.Function keyMapper, Throwables.Function valueMapper, final Collector downstream) throws E, E2; /** * * @param keyMapper * @param valueMapper * @param downstream * @param mapFactory * @return * @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 predicate * @return * @see Collectors#partitioningBy(Predicate) */ @ParallelSupported @TerminalOp public abstract Map> partitionTo(final Throwables.Predicate predicate) throws E; /** * * @param predicate * @param downstream * @return * @see Collectors#partitioningBy(Predicate, Collector) */ @ParallelSupported @TerminalOp public abstract Map partitionTo(final Throwables.Predicate predicate, final Collector downstream) throws E; /** * * @param keyMapper * @return * @see Collectors#toMultimap(Function, Function) */ @ParallelSupported @TerminalOp public abstract ListMultimap toMultimap(Throwables.Function keyMapper) throws E; /** * * @param keyMapper * @param mapFactory * @return * @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 keyMapper * @param valueMapper * @return * @see Collectors#toMultimap(Function, Function) */ @ParallelSupported @TerminalOp public abstract ListMultimap toMultimap(Throwables.Function keyMapper, Throwables.Function valueMapper) throws E, E2; /** * * @param keyMapper * @param valueMapper * @param mapFactory * @return * @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 entity or map. * * @return * @throws E * @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 entity or map. * * * @param columnNames * @return * @throws E * @see {@link N#newDataSet(Collection, Collection)} */ @SequentialOnly @TerminalOp public abstract DataSet toDataSet(final List columnNames); @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 accumulator * @return * @see #foldLeft(com.landawn.abacus.util.Throwables.BinaryOperator) */ @ParallelSupported @TerminalOp public abstract Optional reduce(BinaryOperator accumulator); /** * * @param identity * @param accumulator * @return * @see #foldLeft(Object, com.landawn.abacus.util.Throwables.BiFunction) */ @ParallelSupported @TerminalOp public T reduce(T identity, BinaryOperator accumulator) { return reduce(identity, accumulator, accumulator); } /** * * @param * @param identity * @param accumulator * @param combiner * @return * @see #foldLeft(Object, com.landawn.abacus.util.Throwables.BiFunction) */ @ParallelSupported @TerminalOp public abstract U reduce(U identity, BiFunction accumulator, BinaryOperator combiner); /** * * @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 * @see #foldLeft(com.landawn.abacus.util.Throwables.BinaryOperator) */ @Beta @ParallelSupported @TerminalOp public abstract Optional reduceUntil(BinaryOperator accumulator, Predicate conditionToBreak); /** * * @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 * @see #foldLeft(Object, com.landawn.abacus.util.Throwables.BiFunction) */ @Beta @ParallelSupported @TerminalOp public T reduceUntil(T identity, BinaryOperator accumulator, Predicate conditionToBreak) { return reduceUntil(identity, accumulator, accumulator, conditionToBreak); } /** * * @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 * @see #foldLeft(Object, com.landawn.abacus.util.Throwables.BiFunction) */ @Beta @ParallelSupported @TerminalOp public abstract U reduceUntil(U identity, BiFunction accumulator, BinaryOperator combiner, Predicate conditionToBreak); /** * * @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); /** * * @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 * @return * @see #collect(Supplier, BiConsumer, BiConsumer) */ @ParallelSupported @TerminalOp public abstract R collect(Supplier supplier, BiConsumer accumulator); @ParallelSupported @TerminalOp public abstract R collect(Collector collector); @ParallelSupported @TerminalOp public abstract R collect(java.util.stream.Collector collector); @ParallelSupported @TerminalOp public abstract RR collectAndThen(Collector downstream, Throwables.Function func) throws E; @ParallelSupported @TerminalOp public abstract RR collectAndThen(java.util.stream.Collector downstream, Throwables.Function func) throws E; @SequentialOnly @TerminalOp public abstract R toListAndThen(Throwables.Function, R, E> func) throws E; @SequentialOnly @TerminalOp public abstract R toSetAndThen(Throwables.Function, R, E> func) throws E; @SequentialOnly @TerminalOp public abstract , E extends Exception> R toCollectionAndThen(Supplier supplier, Throwables.Function func) throws E; @ParallelSupported @TerminalOp public abstract Optional min(Comparator comparator); @ParallelSupported @TerminalOp @SuppressWarnings("rawtypes") public Optional minBy(final Function keyMapper) { final Comparator comparator = Fn.comparingBy(keyMapper); return min(comparator); } @ParallelSupported @TerminalOp public abstract List minAll(Comparator comparator); @ParallelSupported @TerminalOp public abstract Optional max(Comparator comparator); @ParallelSupported @TerminalOp @SuppressWarnings("rawtypes") public Optional maxBy(final Function keyMapper) { final Comparator comparator = Fn.comparingBy(keyMapper); return max(comparator); } @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); @ParallelSupported @TerminalOp public abstract long sumInt(ToIntFunction mapper); @ParallelSupported @TerminalOp public abstract long sumLong(ToLongFunction mapper); @ParallelSupported @TerminalOp public abstract double sumDouble(ToDoubleFunction mapper); @ParallelSupported @TerminalOp public abstract OptionalDouble averageInt(ToIntFunction mapper); @ParallelSupported @TerminalOp public abstract OptionalDouble averageLong(ToLongFunction mapper); @ParallelSupported @TerminalOp public abstract OptionalDouble averageDouble(ToDoubleFunction mapper); @SequentialOnly @TerminalOp public abstract Optional> percentiles(Comparator comparator); @SequentialOnly @TerminalOp public abstract boolean hasDuplicates(); // It won't work for findFirst/only/anyMatch... // @ParallelSupported // @TerminalOp // public abstract Pair countAnd(Throwables.Function, 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(); @SequentialOnly @IntermediateOp public abstract Stream> orderedPermutations(Comparator comparator); @SequentialOnly @IntermediateOp @SafeVarargs public final Stream> cartesianProduct(Collection... cs) { return cartesianProduct(Arrays.asList(cs)); } /** * The time complexity is O(n * m) : n is the size of this Stream and m is the size of specified collection b. * * @param * @param b * @return */ @SequentialOnly @IntermediateOp public abstract Stream> crossJoin(Collection b); /** * The time complexity is O(n * m) : n is the size of this Stream and m is the size of specified collection b. * * @param * @param * @param b * @param func * @return */ @SequentialOnly @IntermediateOp public abstract Stream crossJoin(Collection b, BiFunction func); /** * The time complexity is O(n * m) : n is the size of this Stream and m is the size of specified collection b. * * @param * @param * @param b will be loaded to memory. If {@code b} is too big to load to memory, please use {@code b.cronJoin(this, ...)}. It will be closed along with this {@code Stream}. * @param func * @return */ @SequentialOnly @IntermediateOp public abstract Stream crossJoin(Stream b, BiFunction func); /** * * The time complexity is O(n + m) : n is the size of this Stream and m is the size of specified collection b. * * @param * @param * @param b * @param leftKeyMapper * @param rightKeyMapper * @return * @see
Stream innerJoin(Collection b, Function leftKeyMapper, Function rightKeyMapper, final BiFunction func); /** * * The time complexity is O(n + m) : n is the size of this Stream and m is the size of specified collection b. * * @param * @param b * @param keyMapper * @return * @see Stream innerJoin(Collection b, Function keyMapper, final BiFunction func); /** * * The time complexity is O(n + m) : n is the size of this Stream and m is the size of specified collection b. * * @param * @param * @param * @param b will be loaded to memory. If {@code b} is too big to load to memory, please use {@code b.innerJoin(this, ...)}. It will be closed along with this {@code Stream}. * @param leftKeyMapper * @param rightKeyMapper * @param func * @return * @see O(n * m). You should try {@code innerJoin(Collection, Function, Function)} first. */ @Deprecated @ParallelSupported @IntermediateOp public abstract Stream> innerJoin(Collection b, BiPredicate predicate); /** * * The time complexity is O(n * m) : n is the size of this Stream and m is the size of specified collection b. * * @param * @param b * @param innerJoin * @param * @return * @see Stream> fullJoin(Collection b, Function leftKeyMapper, Function rightKeyMapper); /** * * The time complexity is O(n + m) : n is the size of this Stream and m is the size of specified collection b. * * @param * @param * @param * @param b * @param leftKeyMapper * @param rightKeyMapper * @param func * @return * @see Stream> fullJoin(Collection b, Function keyMapper); /** * * The time complexity is O(n + m) : n is the size of this Stream and m is the size of specified collection b. * * @param * @param * @param b * @param keyMapper * @param func * @return * @see Stream fullJoin(Stream b, Function leftKeyMapper, Function rightKeyMapper, final BiFunction func); /** * The time complexity is O(n * m) : n is the size of this Stream and m is the size of specified collection b. * * @param * @param b * @param predicate * @return * @see O(n * m). You should try {@code fullJoin(Collection, Function, Function, BiFunction)} first. */ @Deprecated @ParallelSupported @IntermediateOp public abstract Stream fullJoin(Collection b, BiPredicate predicate, final BiFunction func); /** * * The time complexity is O(n + m) : n is the size of this Stream and m is the size of specified collection b. * * @param * @param * @param b * @param leftKeyMapper * @param rightKeyMapper * @return * @see Stream leftJoin(Collection b, Function leftKeyMapper, Function rightKeyMapper, final BiFunction func); /** * * The time complexity is O(n + m) : n is the size of this Stream and m is the size of specified collection b. * * @param * @param b * @param keyMapper * @return * @see Stream leftJoin(Collection b, Function keyMapper, final BiFunction func); /** * * The time complexity is O(n + m) : n is the size of this Stream and m is the size of specified collection b. * * @param * @param * @param * @param b will be loaded to memory. If {@code b} is too big to load to memory, please use {@code b.leftJoin(this, ...)}. It will be closed along with this {@code Stream}. * @param leftKeyMapper * @param rightKeyMapper * @param func * @return * @see O(n * m). You should try {@code leftJoin(Collection, Function, Function)} first. */ @Deprecated @ParallelSupported @IntermediateOp public abstract Stream> leftJoin(Collection b, BiPredicate predicate); /** * * The time complexity is O(n * m) : n is the size of this Stream and m is the size of specified collection b. * * @param * @param b * @param innerJoin * @param * @return * @see Stream> rightJoin(Collection b, Function leftKeyMapper, Function rightKeyMapper); /** * * The time complexity is O(n + m) : n is the size of this Stream and m is the size of specified collection b. * * @param * @param * @param * @param b * @param leftKeyMapper * @param rightKeyMapper * @param func * @return * @see Stream> rightJoin(Collection b, Function keyMapper); /** * * The time complexity is O(n + m) : n is the size of this Stream and m is the size of specified collection b. * * @param * @param * @param b * @param keyMapper * @param func * @return * @see Stream rightJoin(Stream b, Function leftKeyMapper, Function rightKeyMapper, final BiFunction func); /** * The time complexity is O(n * m) : n is the size of this Stream and m is the size of specified collection b. * * @param * @param b * @param predicate * @return * @see O(n * m). You should try {@code rightJoin(Collection, Function, Function, BiFunction)} first. */ @Deprecated @ParallelSupported @IntermediateOp public abstract Stream rightJoin(Collection b, BiPredicate predicate, final BiFunction func); /** * The time complexity is O(n + m) : n is the size of this Stream and m is the size of specified collection b. * * @param * @param * @param b * @param leftKeyMapper * @param rightKeyMapper * @return */ @ParallelSupported @IntermediateOp public abstract Stream>> groupJoin(Collection b, Function leftKeyMapper, Function rightKeyMapper); /** * The time complexity is O(n + m) : n is the size of this Stream and m is the size of specified collection b. * * @param * @param * @param * @param b * @param leftKeyMapper * @param rightKeyMapper * @return */ @ParallelSupported @IntermediateOp public abstract Stream groupJoin(Collection b, Function leftKeyMapper, Function rightKeyMapper, final BiFunction, R> func); /** * The time complexity is O(n + m) : n is the size of this Stream and m is the size of specified collection b. * * @param * @param b * @param keyMapper * @return * @see Stream groupJoin(Collection b, Function keyMapper, final BiFunction, R> func); /** * The time complexity is O(n + m) : n is the size of this Stream and m is the size of specified collection b. * * @param * @param * @param * @param b will be loaded to memory. If {@code b} is too big to load to memory, please use {@code b.groupJoin(this, ...)}. It will be closed along with this {@code Stream}. * @param leftKeyMapper * @param rightKeyMapper * @return */ @ParallelSupported @IntermediateOp public abstract Stream groupJoin(Stream b, Function leftKeyMapper, Function rightKeyMapper, final BiFunction, R> func); /** * The time complexity is O(n + m) : n is the size of this Stream and m is the size of specified collection b. * * @param * @param * @param b * @param leftKeyMapper * @param rightKeyMapper * @param mergeFunction * @return */ @ParallelSupported @IntermediateOp public abstract Stream> groupJoin(Collection b, Function leftKeyMapper, Function rightKeyMapper, BinaryOperator mergeFunction); /** * The time complexity is O(n + m) : n is the size of this Stream and m is the size of specified collection b. * * @param * @param * @param * @param b * @param leftKeyMapper * @param rightKeyMapper * @param mergeFunction * @param func * @return */ @ParallelSupported @IntermediateOp public abstract Stream groupJoin(Collection b, Function leftKeyMapper, Function rightKeyMapper, BinaryOperator mergeFunction, final BiFunction func); /** * The time complexity is O(n + m) : n is the size of this Stream and m is the size of specified collection b. * * @param * @param * @param * @param b * @param leftKeyMapper * @param rightKeyMapper * @param mergeFunction * @param func * @return */ @ParallelSupported @IntermediateOp public abstract Stream groupJoin(Stream b, Function leftKeyMapper, Function rightKeyMapper, BinaryOperator mergeFunction, final BiFunction func); /** * The time complexity is O(n + m) : n is the size of this Stream and m is the size of specified collection b. * * @param * @param * @param * @param * @param b * @param leftKeyMapper * @param rightKeyMapper * @param downstream * @return */ @ParallelSupported @IntermediateOp public abstract Stream> groupJoin(Collection b, Function leftKeyMapper, Function rightKeyMapper, Collector downstream); /** * The time complexity is O(n + m) : n is the size of this Stream and m is the size of specified collection b. * * @param * @param * @param * @param * @param * @param b * @param leftKeyMapper * @param rightKeyMapper * @param downstream * @param func * @return */ @ParallelSupported @IntermediateOp public abstract Stream groupJoin(Collection b, Function leftKeyMapper, Function rightKeyMapper, Collector downstream, final BiFunction func); /** * The time complexity is O(n + m) : n is the size of this Stream and m is the size of specified collection b. * * @param * @param * @param * @param * @param * @param b will be loaded to memory. If {@code b} is too big to load to memory, please use {@code b.groupJoin(this, ...)}. It will be closed along with this {@code Stream}. * @param leftKeyMapper * @param rightKeyMapper * @param downstream * @param func * @return */ @ParallelSupported @IntermediateOp public abstract Stream groupJoin(Stream b, Function leftKeyMapper, Function rightKeyMapper, Collector downstream, final BiFunction func); /** * * @param * @param b should be ordered * @param predicate check if the element from {@code b} can be joined with current element from {@code this Stream}. * @return */ @Beta @SequentialOnly @IntermediateOp public abstract Stream>> joinByRange(final Iterator b, final BiPredicate predicate); /** * * @param * @param * @param * @param b should be ordered * @param predicate check if the element from {@code b} can be joined with current element from {@code this Stream}. * @param collector * @return */ @Beta @SequentialOnly @IntermediateOp public abstract Stream> joinByRange(final Iterator b, final BiPredicate predicate, final Collector collector); /** * * @param * @param * @param * @param * @param b should be ordered * @param predicate check if the element from {@code b} can be joined with current element from {@code this Stream}. * @param collector * @param func * @return */ @Beta @SequentialOnly @IntermediateOp public abstract Stream joinByRange(final Iterator b, final BiPredicate predicate, final Collector collector, BiFunction func); /** * * @param * @param * @param * @param * @param b should be ordered. It will be closed along with this {@code Stream} * @param predicate check if the element from {@code b} can be joined with current element from {@code this Stream}. * @param collector * @param func * @param mapperForUnJoinedEelements * In a lot of scenarios, there could be an previous element which is took out from the specified {@code Iterator b} but not joined, you may need to consider including that element in this {@code mapperForUnJoinedEelements}. *
* This input {@code Iterator} is the input {@code b} * @return */ @Beta @SequentialOnly @IntermediateOp public abstract Stream joinByRange(final Iterator b, final BiPredicate predicate, final Collector collector, BiFunction func, Function, Stream> mapperForUnJoinedEelements); /** * * @param * @param b should be ordered. It will be closed along with this {@code Stream} * @param predicate check if the element from {@code b} can be joined with current element from {@code this Stream}. * @return */ @Beta @SequentialOnly @IntermediateOp public abstract Stream>> joinByRange(final Stream b, final BiPredicate predicate); /** * * @param * @param
* @param * @param b should be ordered. It will be closed along with this {@code Stream} * @param predicate check if the element from {@code b} can be joined with current element from {@code this Stream}. * @param collector * @return */ @Beta @SequentialOnly @IntermediateOp public abstract Stream> joinByRange(final Stream b, final BiPredicate predicate, final Collector collector); /** * * @param * @param * @param * @param * @param b should be ordered. It will be closed along with this {@code Stream} * @param predicate check if the element from {@code b} can be joined with current element from {@code this Stream}. * @param collector * @param func * @return */ @Beta @SequentialOnly @IntermediateOp public abstract Stream joinByRange(final Stream b, final BiPredicate predicate, final Collector collector, final BiFunction func); /** * * @param * @param * @param * @param * @param b should be ordered. It will be closed along with this {@code Stream} * @param predicate check if the element from {@code b} can be joined with current element from {@code this Stream}. * @param collector * @param func * @param mapperForUnJoinedEelements * In a lot of scenarios, there could be an previous element which is took out from the specified {@code Iterator b} but not joined, you may need to consider including that element in this {@code mapperForUnJoinedEelements}. *
* This input {@code Iterator} comes from {@code b.iterator()}. * @return */ @Beta @SequentialOnly @IntermediateOp public abstract Stream joinByRange(final Stream b, final BiPredicate predicate, final Collector collector, final BiFunction func, Function, Stream> mapperForUnJoinedEelements); /** * * If there is no value to join and want to skip that element, {@code joinFunc} can return {@code null} and then skip the {@code null} element by {@code stream.join(b, joinFunc).skipNull()}. * * @param * @param * @param b * @param joinFunc * @return */ @Beta @ParallelSupported @IntermediateOp public abstract , R> Stream join(final B b, final BiFunction joinFunc); /** * If there is no value to join and want to skip that element, {@code joinFunc} can return {@code null} and then skip the {@code null} element by {@code stream.join(b, joinFunc).skipNull()}. * * * @param * @param * @param b * @param joinFunc * @return */ @Beta @ParallelSupported @IntermediateOp public abstract , R> Stream join(final B b, final BiFunction joinFunc); /** * If there is no value to join and want to skip that element, {@code joinFunc} can return {@code null} and then skip the {@code null} element by {@code stream.join(b, joinFunc).skipNull()}. * * * @param * @param * @param b should be ordered * @param joinFunc * @return */ @Beta @SequentialOnly @IntermediateOp public abstract , R> Stream join(final B b, final BiFunction joinFunc); /** * If there is no value to join and want to skip that element, {@code joinFunc} can return {@code null} and then skip the {@code null} element by {@code stream.join(b, joinFunc).skipNull()}. * * * @param * @param * @param b should be ordered * @param joinFunc * @param mapperForUnJoinedEelements In a lot of scenarios, there could be an previous element which is took out from the specified {@code Iterator b} but not joined, you may need to consider including that element in this {@code mapperForUnJoinedEelements} * @return */ @Beta @SequentialOnly @IntermediateOp public abstract , R> Stream join(final B b, final BiFunction joinFunc, Function, Stream> mapperForUnJoinedEelements); /** * If there is no value to join and want to skip that element, {@code joinFunc} can return {@code null} and then skip the {@code null} element by {@code stream.join(b, joinFunc).skipNull()}. * * * @param * @param b should be ordered. It will be closed along with this stream. It can also be closed earlier by {@code joinFunc}. * @param joinFunc * @return */ @Beta @SequentialOnly @IntermediateOp public abstract Stream join(final Stream b, final BiFunction, R> joinFunc); /** * If there is no value to join and want to skip that element, {@code joinFunc} can return {@code null} and then skip the {@code null} element by {@code stream.join(b, joinFunc).skipNull()}. * * * @param * @param b should be ordered. It will be closed along with this stream. It can also be closed earlier by {@code joinFunc}. * @param joinFunc * @param mapperForUnJoinedEelements * In a lot of scenarios, there could be an previous element which is took out from the specified {@code Iterator b} but not joined, you may need to consider including that element in this {@code mapperForUnJoinedEelements}. *
* This input {@code Iterator} comes from {@code b.iterator()}. * @return */ @Beta @SequentialOnly @IntermediateOp public abstract Stream join(final Stream b, final BiFunction, R> joinFunc, Function, Stream> mapperForUnJoinedEelements); @SequentialOnly @IntermediateOp public abstract Stream> cartesianProduct(Collection> cs); @SequentialOnly @IntermediateOp public abstract Stream peekFirst(Consumer action); @SequentialOnly @IntermediateOp public abstract Stream peekLast(Consumer action); /** * Intersect with the specified Collection by the values mapped by mapper. * * @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 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); @SequentialOnly @IntermediateOp @SafeVarargs public final Stream prepend(T... a) { return prepend(Arrays.asList(a)); } @SequentialOnly @IntermediateOp public abstract Stream prepend(Collection c); @SequentialOnly @IntermediateOp @SafeVarargs public final Stream append(T... a) { return append(Arrays.asList(a)); } @SequentialOnly @IntermediateOp public abstract Stream append(Collection c); // @SequentialOnly // public abstract Stream appendAlll(Collection> cs); // @SequentialOnly // public abstract Stream prependAlll(Collection> cs); @SequentialOnly @IntermediateOp @SafeVarargs public final Stream appendIfEmpty(T... a) { return appendIfEmpty(Arrays.asList(a)); } @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, 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; @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); @ParallelSupported @IntermediateOp public abstract Stream zipWith(final Collection b, final BiFunction zipFunction); @ParallelSupported @IntermediateOp public abstract Stream zipWith(final Collection b, final T valueForNoneA, final T2 valueForNoneB, final BiFunction zipFunction); @ParallelSupported @IntermediateOp public abstract Stream zipWith(final Stream b, final BiFunction zipFunction); @ParallelSupported @IntermediateOp public abstract Stream zipWith(final Stream b, final T valueForNoneA, final T2 valueForNoneB, final BiFunction zipFunction); @ParallelSupported @IntermediateOp public abstract Stream zipWith(final Stream b, final Stream c, final TriFunction zipFunction); @ParallelSupported @IntermediateOp public abstract Stream zipWith(final Stream b, final Stream c, final T valueForNoneA, final T2 valueForNoneB, final T3 valueForNoneC, final TriFunction zipFunction); @SequentialOnly @TerminalOp public abstract long persist(File file) 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; @SequentialOnly @TerminalOp public abstract long persist(Throwables.Function toLine, String header, String tail, File file) 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; @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 batchInterval * @param stmtSetter * @return * @throws SQLException */ @SequentialOnly @TerminalOp public abstract long persist(final Connection conn, final String insertSQL, final int batchSize, final int batchInterval, final Throwables.BiConsumer stmtSetter) throws SQLException; /** * * @param stmt * @param batchSize * @param batchInterval * @param stmtSetter * @return * @throws SQLException */ @SequentialOnly @TerminalOp public abstract long persist(final PreparedStatement stmt, final int batchSize, final int batchInterval, final Throwables.BiConsumer stmtSetter) throws SQLException; /** * Remember to close this Stream after the iteration is done, if needed. * * @return */ @SequentialOnly @IntermediateOp public abstract java.util.stream.Stream toJdkStream(); /** * * @param * @param cls * @return */ @SequentialOnly @Beta @IntermediateOp public ExceptionalStream checked() { return ExceptionalStream. of(this); } /** * * @param * @param exceptionType * @return */ @SequentialOnly @Beta @IntermediateOp public ExceptionalStream checked(final Class exceptionType) { return ExceptionalStream. 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(); if (this.isParallel() && maxThreadNum == maxThreadNum()) { return split(bufferSize).flatMap(s -> op.apply(s)).sequential(); } else { return split(bufferSize).parallel(maxThreadNum, splitor(), asyncExecutor(), cancelUncompletedThreads()).flatMap(s -> op.apply(s)).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().flattMap(mapper).sequence()} * * @param * @param mapper * @return * @see #sps(Function) */ @Beta @IntermediateOp public Stream spsFlattMap(final Function> mapper) { return sps(s -> s.flattMap(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).flattMap(mapper).sequence()} * * @param * @param maxThreadNum * @param mapper * @return * @see #sps(int, Function) */ @Beta @IntermediateOp public Stream spsFlattMap(final int maxThreadNum, final Function> mapper) { return sps(maxThreadNum, s -> s.flattMap(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 * @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.flattMap(mapper)).sequential()} * * @param * @param maxThreadNum * @param bufferSize * @param mapper * @return * @see #sps(int, int, Function) */ @Beta @IntermediateOp public Stream spsFlattMap(final int maxThreadNum, final int bufferSize, final Function> mapper) { return sps(maxThreadNum, bufferSize, s -> s.flattMap(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 * @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().flattMapE(mapper).sequence()} * * @param * @param mapper * @return * @see #sps(Function) */ @Beta @IntermediateOp public Stream spsFlattMapE(final Throwables.Function, ? extends Exception> mapper) { return sps(s -> s.flattMapE(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().flattMapE(mapper).sequence()} * * @param * @param maxThreadNum * @param mapper * @return * @see #sps(Function) */ @Beta @IntermediateOp public Stream spsFlattMapE(final int maxThreadNum, final Throwables.Function, ? extends Exception> mapper) { return sps(maxThreadNum, s -> s.flattMapE(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)); } /** * * @param predicate * @return * @see Fn#pp(com.landawn.abacus.util.Throwables.Predicate) */ @Beta @ParallelSupported @IntermediateOp public Stream filterE(final Throwables.Predicate predicate) { return filter(Fn.pp(predicate)); } /** * * @param * @param mapper * @return * @see Fn#ff(com.landawn.abacus.util.Throwables.Function) */ @Beta @ParallelSupported @IntermediateOp public Stream mapE(final Throwables.Function mapper) { return map(Fn.ff(mapper)); } /** * * @param * @param mapper * @return * @see Fn#ff(com.landawn.abacus.util.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(com.landawn.abacus.util.Throwables.Function) */ @Beta @ParallelSupported @IntermediateOp public Stream flattMapE(final Throwables.Function, ? extends Exception> mapper) { return flattMap(Fn.ff(mapper)); } /** * * @param * @param action * @return * @see Fn#cc(com.landawn.abacus.util.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 keyMapper * @param valueMapper * @return * * @see DisposableEntry * @see NoCachingNoUpdating * * @deprecated */ @SequentialOnly @Beta @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 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 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); } public static Stream empty() { return new ArrayStream<>((T[]) N.EMPTY_OBJECT_ARRAY, true, NATURAL_COMPARATOR, null); } 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); } @SafeVarargs public static Stream of(final T... a) { return N.isNullOrEmpty(a) ? (Stream) empty() : of(a, 0, a.length); } /** * * @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 c * @return */ public static Stream of(final Collection c) { return N.isNullOrEmpty(c) ? (Stream) empty() : of(c, 0, c.size()); } /** * * @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); } } 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()); } 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 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); } 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()); } 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(); } }); } public static Stream of(final boolean[] a) { if (N.isNullOrEmpty(a)) { return empty(); } return of(a, 0, a.length); } 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; } @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; } }); } public static Stream of(char[] a) { if (N.isNullOrEmpty(a)) { return empty(); } return of(a, 0, a.length); } 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; } @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; } }); } public static Stream of(byte[] a) { if (N.isNullOrEmpty(a)) { return empty(); } return of(a, 0, a.length); } 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; } @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; } }); } public static Stream of(short[] a) { if (N.isNullOrEmpty(a)) { return empty(); } return of(a, 0, a.length); } 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; } @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; } }); } public static Stream of(int[] a) { if (N.isNullOrEmpty(a)) { return empty(); } return of(a, 0, a.length); } 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; } @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; } }); } public static Stream of(long[] a) { if (N.isNullOrEmpty(a)) { return empty(); } return of(a, 0, a.length); } 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; } @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; } }); } public static Stream of(float[] a) { if (N.isNullOrEmpty(a)) { return empty(); } return of(a, 0, a.length); } 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; } @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; } }); } public static Stream of(double[] a) { if (N.isNullOrEmpty(a)) { return empty(); } return of(a, 0, a.length); } 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; } @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; } }); } public static Stream of(final Optional op) { return op == null || !op.isPresent() ? Stream. empty() : Stream.of(op.get()); } public static Stream of(final java.util.Optional op) { return op == null || !op.isPresent() ? Stream. empty() : Stream.of(op.get()); } public static Stream ofKeys(final Map map) { if (N.isNullOrEmpty(map)) { return Stream.empty(); } return of(map.keySet()); } public static Stream ofKeys(final Map map, final Predicate valueFilter) { if (N.isNullOrEmpty(map)) { return StreamEx.empty(); } return EntryStream. of(map).filterByValue(valueFilter).keys(); } public static Stream ofKeys(final Map map, final BiPredicate filter) { if (N.isNullOrEmpty(map)) { return StreamEx.empty(); } return EntryStream. of(map).filter(filter).keys(); } public static Stream ofValues(final Map map) { if (N.isNullOrEmpty(map)) { return Stream.empty(); } return of(map.values()); } public static Stream ofValues(final Map map, final Predicate keyFilter) { if (N.isNullOrEmpty(map)) { return Stream.empty(); } return EntryStream. of(map).filterByKey(keyFilter).values(); } 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).flattMap(it -> it.get())}. * * @param supplier * @return */ @Beta public static Stream from(final Supplier> supplier) { N.checkArgNotNull(supplier, "supplier"); return Stream.just(supplier).flattMap(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); } public static Stream range(final int startInclusive, final int endExclusive) { return IntStream.range(startInclusive, endExclusive).boxed(); } public static Stream range(final int startInclusive, final int endExclusive, final int by) { return IntStream.range(startInclusive, endExclusive, by).boxed(); } public static Stream range(final long startInclusive, final long endExclusive) { return LongStream.range(startInclusive, endExclusive).boxed(); } public static Stream range(final long startInclusive, final long endExclusive, final long by) { return LongStream.range(startInclusive, endExclusive, by).boxed(); } public static Stream rangeClosed(final int startInclusive, final int endInclusive) { return IntStream.rangeClosed(startInclusive, endInclusive).boxed(); } public static Stream rangeClosed(final int startInclusive, final int endInclusive, final int by) { return IntStream.rangeClosed(startInclusive, endInclusive, by).boxed(); } public static Stream rangeClosed(final long startInclusive, final long endInclusive) { return LongStream.rangeClosed(startInclusive, endInclusive).boxed(); } public static Stream rangeClosed(final long startInclusive, final long endInclusive, final long by) { return LongStream.rangeClosed(startInclusive, endInclusive, by).boxed(); } public static Stream split(final CharSequence str, final CharSequence delimiter) { return Splitter.with(delimiter).splitToStream(str); } public static Stream flatten(final Collection> c) { return of(c).flattMap(Fn.> identity()); } public static Stream flatten(final T[][] a) { return of(a).flatMapp(Fn. identity()); } 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).flatMapp(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); } 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 = 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); } public static Stream flatten(final T[][][] a) { return of(a).flatMapp(e -> e).flatMapp(Fn. identity()); } 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; } }); } 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 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 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; } }); } 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); } }); } 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 intervalInMillis * @param s * @return */ public static Stream interval(final long intervalInMillis, final Supplier s) { return interval(0, intervalInMillis, s); } /** * * @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 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()); } public static Stream interval(final long intervalInMillis, final LongFunction s) { return interval(0, intervalInMillis, s); } /** * * @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 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); } public static Stream lines(final File file) throws UncheckedIOException { return lines(file, Charsets.UTF_8); } 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()); } public static Stream lines(final Path path) throws UncheckedIOException { return lines(path, Charsets.UTF_8); } 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; { 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; } }); } public static Stream listFiles(final File parentPath) throws UncheckedIOException { if (!parentPath.exists()) { return empty(); } return of(parentPath.listFiles()); } 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); } /** * * @param * @param queue * @param duration * @return * @see com.landawn.abacus.util.Observer */ @Beta public static Stream observe(final BlockingQueue queue, final Duration duration) { return observe(queue, duration, Fn.emptyAction()); } /** * 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 queue * @param duration * @param onComplete * @return * @see com.landawn.abacus.util.Observer */ @Beta public static Stream observe(final BlockingQueue queue, final Duration duration, final Runnable onComplete) { N.checkArgNotNull(queue, "queue"); N.checkArgNotNull(duration, "duration"); N.checkArgNotNull(onComplete, "onComplete"); 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).onClose(onComplete); } /** * * @param * @param queue * @param hasMore * @param maxWaitIntervalInMillis * @return * @see com.landawn.abacus.util.Observer */ @Beta public static Stream observe(final BlockingQueue queue, final BooleanSupplier hasMore, final long maxWaitIntervalInMillis) { return observe(queue, hasMore, maxWaitIntervalInMillis, Fn.emptyAction()); } /** * 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 queue * @param hasMore * @param maxWaitIntervalInMillis * @param isCompleted 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. * @return * @see com.landawn.abacus.util.Observer */ @Beta public static Stream observe(final BlockingQueue queue, final BooleanSupplier hasMore, final long maxWaitIntervalInMillis, final Runnable onComplete) { N.checkArgNotNull(queue, "queue"); N.checkArgNotNull(hasMore, "hasMore"); N.checkArgPositive(maxWaitIntervalInMillis, "maxWaitIntervalInMillis"); N.checkArgNotNull(onComplete, "onComplete"); 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).onClose(onComplete); } @SafeVarargs public static Stream concat(final T[]... a) { if (N.isNullOrEmpty(a)) { return empty(); } return of(Iterators.concat(a)); } @SafeVarargs public static Stream concat(final Iterable... a) { if (N.isNullOrEmpty(a)) { return empty(); } return of(Iterators.concat(a)); } @SafeVarargs public static Stream concat(final Iterator... a) { if (N.isNullOrEmpty(a)) { return empty(); } return of(Iterators.concat(a)); } @SafeVarargs public static Stream concat(final Stream... a) { if (N.isNullOrEmpty(a)) { return empty(); } return concat(Array.asList(a)); } 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)); } @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(); } }); } @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 a * @return */ @SafeVarargs public static Stream parallelConcat(final Iterable... a) { return parallelConcat(a, DEFAULT_READING_THREAD_NUM, calculateBufferedSize(a.length)); } /** * * @param a * @param readThreadNum - count of threads used to read elements from iterator to queue. Default value is min(8, a.length) * @param bufferedSize * @return */ public static Stream parallelConcat(final Iterable[] a, final int readThreadNum, final int bufferedSize) { if (N.isNullOrEmpty(a)) { return empty(); } return parallelConcatIterables(Array.asList(a), readThreadNum, bufferedSize); } /** * * @param a * @return */ @SafeVarargs public static Stream parallelConcat(final Iterator... a) { return parallelConcat(a, DEFAULT_READING_THREAD_NUM, calculateBufferedSize(a.length)); } /** * * @param a * @param readThreadNum - count of threads used to read elements from iterator to queue. Default value is min(8, a.length) * @param bufferedSize * @return */ public static Stream parallelConcat(final Iterator[] a, final int readThreadNum, final int bufferedSize) { if (N.isNullOrEmpty(a)) { return empty(); } return parallelConcatIterators(Array.asList(a), readThreadNum, bufferedSize); } /** * * @param a * @return */ @SafeVarargs public static Stream parallelConcat(final Stream... a) { return parallelConcat(a, DEFAULT_READING_THREAD_NUM, calculateBufferedSize(a.length)); } /** * Returns a Stream with elements from a temporary queue which is filled by reading the elements from the specified iterators in parallel. * * * @param a * @param readThreadNum - count of threads used to read elements from iterator to queue. Default value is min(8, a.length) * @param bufferedSize * @return */ public static Stream parallelConcat(final Stream[] a, final int readThreadNum, final int bufferedSize) { if (N.isNullOrEmpty(a)) { return empty(); } return parallelConcat(Array.asList(a), readThreadNum, bufferedSize); } /** * * @param c * @return */ public static Stream parallelConcat(final Collection> c) { return parallelConcat(c, DEFAULT_READING_THREAD_NUM); } /** * * @param c * @param readThreadNum * @return */ public static Stream parallelConcat(final Collection> c, final int readThreadNum) { return parallelConcat(c, readThreadNum, calculateBufferedSize(c.size())); } /** * Returns a Stream with elements from a temporary queue which is filled by reading the elements from the specified iterators in parallel. * * @param a * @param readThreadNum - count of threads used to read elements from iterator to queue. Default value is min(8, c.size()) * @param bufferedSize Default value is N.min(128, c.size() * 16) * @return */ public static Stream parallelConcat(final Collection> c, final int readThreadNum, final int bufferedSize) { 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<>(bufferedSize); 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); // 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 - i, futureList, new Throwables.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(bufferedSize) { 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 c * @return */ @Beta public static Stream parallelConcatIterables(final Collection> c) { return parallelConcatIterables(c, DEFAULT_READING_THREAD_NUM); } /** * * @param c * @param readThreadNum * @return */ @Beta public static Stream parallelConcatIterables(final Collection> c, final int readThreadNum) { return parallelConcatIterables(c, readThreadNum, calculateBufferedSize(c.size())); } /** * Returns a Stream with elements from a temporary queue which is filled by reading the elements from the specified iterators in parallel. * * * @param a * @param readThreadNum - count of threads used to read elements from iterator to queue. Default value is min(8, c.size()) * @param bufferedSize Default value is N.min(128, c.size() * 16) * @return */ @Beta public static Stream parallelConcatIterables(final Collection> c, final int readThreadNum, final int bufferedSize) { if (N.isNullOrEmpty(c)) { return Stream.empty(); } return parallelConcatIterators(Stream.of(c).skipNull().map(Iterable::iterator).toList(), readThreadNum, bufferedSize); } /** * * @param c * @return */ public static Stream parallelConcatIterators(final Collection> c) { return parallelConcatIterators(c, DEFAULT_READING_THREAD_NUM); } /** * * @param c * @param readThreadNum * @return */ public static Stream parallelConcatIterators(final Collection> c, final int readThreadNum) { return parallelConcatIterators(c, readThreadNum, false, null); } /** * * @param a * @param readThreadNum - count of threads used to read elements from iterator to queue. Default value is min(8, c.size()) * @param bufferedSize Default value is N.min(128, c.size() * 16) * @return */ public static Stream parallelConcatIterators(final Collection> c, final int readThreadNum, final int bufferedSize) { return parallelConcatIterators(c, readThreadNum, bufferedSize, false, null); } static Stream parallelConcatIterators(final Collection> c, final int readThreadNum, final boolean cancelUncompletedThreads, final AsyncExecutor asyncExecutor) { return parallelConcatIterators(c, readThreadNum, calculateBufferedSize(c.size()), 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 bufferedSize 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 bufferedSize, final boolean cancelUncompletedThreads, final AsyncExecutor asyncExecutor) { 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<>(bufferedSize); final Holder eHolder = new Holder<>(); final MutableBoolean disposableChecked = MutableBoolean.of(false); final Iterator> iterators = c.iterator(); final List> futureList1 = new ArrayList<>(threadNum); final AtomicInteger threadCounter = new AtomicInteger(threadNum); boolean noException = false; AsyncExecutor asyncExecutorToUse = checkAsyncExecutor(asyncExecutor, threadNum); // 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 - i, futureList1, () -> { 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(bufferedSize) { 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 } } finally { if (holderForAsyncExecutorUsed.isNotNull()) { final AsyncExecutor asyncExecutorToUse = holderForAsyncExecutorUsed.value(); shutdownTempExecutor(asyncExecutor, asyncExecutorToUse); } } }); } /** * Zip together the "a" and "b" arrays until one of them runs out of values. * Each pair of values is combined into a single value using the supplied zipFunction function. * * @param a * @param b * @return */ public static 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 a * @param b * @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 a * @param b * @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 a * @param b * @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 a * @param b * @return */ public static Stream zip(final CharStream a, final CharStream b, final CharBiFunction zipFunction) { return 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 a * @param b * @return */ public static Stream zip(final CharStream a, final CharStream b, final CharStream c, final CharTriFunction zipFunction) { return 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 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 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 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 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 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 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 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 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 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 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 a * @param b * @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 a * @param b * @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 a * @param b * @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 a * @param b * @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 a * @param b * @return */ public static Stream zip(final ByteStream a, final ByteStream b, final ByteBiFunction zipFunction) { return 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 a * @param b * @return */ public static Stream zip(final ByteStream a, final ByteStream b, final ByteStream c, final ByteTriFunction zipFunction) { return 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 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 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 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 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 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 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 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 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 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 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 a * @param b * @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 a * @param b * @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 a * @param b * @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 a * @param b * @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 a * @param b * @return */ public static Stream zip(final ShortStream a, final ShortStream b, final ShortBiFunction zipFunction) { return 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 a * @param b * @return */ public static Stream zip(final ShortStream a, final ShortStream b, final ShortStream c, final ShortTriFunction zipFunction) { return 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 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 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 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 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 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 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 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 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 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 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 a * @param b * @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 a * @param b * @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 a * @param b * @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 a * @param b * @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 a * @param b * @return */ public static Stream zip(final IntStream a, final IntStream b, final IntBiFunction zipFunction) { return 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 a * @param b * @return */ public static Stream zip(final IntStream a, final IntStream b, final IntStream c, final IntTriFunction zipFunction) { return 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 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 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 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 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 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 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 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 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 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 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 a * @param b * @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 a * @param b * @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 a * @param b * @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 a * @param b * @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 a * @param b * @return */ public static Stream zip(final LongStream a, final LongStream b, final LongBiFunction zipFunction) { return 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 a * @param b * @return */ public static Stream zip(final LongStream a, final LongStream b, final LongStream c, final LongTriFunction zipFunction) { return 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 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 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 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 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 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 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 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 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 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 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 a * @param b * @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 a * @param b * @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 a * @param b * @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 a * @param b * @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 a * @param b * @return */ public static Stream zip(final FloatStream a, final FloatStream b, final FloatBiFunction zipFunction) { return 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 a * @param b * @return */ public static Stream zip(final FloatStream a, final FloatStream b, final FloatStream c, final FloatTriFunction zipFunction) { return 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 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 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 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 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 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 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 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 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 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 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 a * @param b * @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 a * @param b * @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 a * @param b * @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 a * @param b * @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 a * @param b * @return */ public static Stream zip(final DoubleStream a, final DoubleStream b, final DoubleBiFunction zipFunction) { return 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 a * @param b * @return */ public static Stream zip(final DoubleStream a, final DoubleStream b, final DoubleStream c, final DoubleTriFunction zipFunction) { return 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 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 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 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 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 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 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 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 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 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 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 a * @param b * @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 a * @param b * @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 a * @param b * @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 a * @param b * @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 a * @param b * @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 a * @param b * @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 a * @param b * @return */ public static Stream zip(final Stream a, final Stream b, final BiFunction zipFunction) { return 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 a * @param b * @return */ public static Stream zip(final Stream a, final Stream b, final Stream c, final TriFunction zipFunction) { return 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 c * @param zipFunction * @return */ public static Stream zip(final Collection> c, final Function, 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 zipIterators(iterList, zipFunction).onClose(newCloseHandler(c)); } public static Stream zipIterables(final Collection> collections, final Function, 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); } public static Stream zipIterators(final Collection> iterators, final Function, 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 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 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 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 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 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 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 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 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 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 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 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, 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, 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 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, 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(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @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(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param a * @param b * @param zipFunction * @param bufferedSize * @return */ public static Stream parallelZip(final Iterable a, final Iterable b, final BiFunction zipFunction, final int bufferedSize) { return parallelZip(N.iterate(a), N.iterate(b), zipFunction, bufferedSize); } /** * 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(..., 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(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param a * @param b * @param c * @param zipFunction * @param bufferedSize * @return */ public static Stream parallelZip(final Iterable a, final Iterable b, final Iterable c, final TriFunction zipFunction, final int bufferedSize) { return parallelZip(N.iterate(a), N.iterate(b), N.iterate(c), zipFunction, bufferedSize); } /** * 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(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param a * @param b * @param zipFunction * @return */ 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(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param a * @param b * @param zipFunction * @param bufferedSize * @return */ public static Stream parallelZip(final Iterator a, final Iterator b, final BiFunction zipFunction, final int bufferedSize) { final AtomicInteger threadCounterA = new AtomicInteger(1); final AtomicInteger threadCounterB = new AtomicInteger(1); final BlockingQueue queueA = new ArrayBlockingQueue<>(bufferedSize); final BlockingQueue queueB = new ArrayBlockingQueue<>(bufferedSize); final Holder eHolder = new Holder<>(); final MutableBoolean onGoing = MutableBoolean.of(true); final Holder holderForAsyncExecutorUsed = new Holder<>(); final Supplier> supplier = () -> { boolean noException = false; try { readToQueue(a, b, DEFAULT_ASYNC_EXECUTOR, threadCounterA, threadCounterB, queueA, queueB, eHolder, onGoing, holderForAsyncExecutorUsed); noException = true; } finally { if (!noException) { onGoing.setFalse(); } } return new BufferedIterator(bufferedSize) { A nextA = null; 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 true; } @Override public R next() { if ((nextA == null || nextB == null) && !hasNext()) { throw new NoSuchElementException(); } boolean isOK = false; try { final R result = zipFunction.apply(nextA == NONE ? null : nextA, nextB == NONE ? null : nextB); nextA = null; nextB = null; isOK = true; return result; } finally { // error happened if (!isOK) { onGoing.setFalse(); } } } }; }; return just(supplier).flatMap(it -> Stream.of(it.get())).onClose(() -> { onGoing.setFalse(); if (holderForAsyncExecutorUsed.isNotNull()) { shutdownTempExecutor(holderForAsyncExecutorUsed.value()); } }); } /** * 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(..., 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(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param a * @param b * @param c * @param zipFunction * @param bufferedSize * @return */ public static Stream parallelZip(final Iterator a, final Iterator b, final Iterator c, final TriFunction zipFunction, final int bufferedSize) { final AtomicInteger threadCounterA = new AtomicInteger(1); final AtomicInteger threadCounterB = new AtomicInteger(1); final AtomicInteger threadCounterC = new AtomicInteger(1); final BlockingQueue queueA = new ArrayBlockingQueue<>(bufferedSize); final BlockingQueue queueB = new ArrayBlockingQueue<>(bufferedSize); final BlockingQueue queueC = new ArrayBlockingQueue<>(bufferedSize); final Holder eHolder = new Holder<>(); final MutableBoolean onGoing = MutableBoolean.of(true); final Holder holderForAsyncExecutorUsed = new Holder<>(); final Supplier> supplier = () -> { 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(); } } return new BufferedIterator(bufferedSize) { A nextA = null; B nextB = null; 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 true; } @Override public R next() { if ((nextA == null || nextB == null || nextC == null) && !hasNext()) { throw new NoSuchElementException(); } boolean isOK = false; try { final R result = zipFunction.apply(nextA == NONE ? null : nextA, nextB == NONE ? null : nextB, nextC == NONE ? null : nextC); nextA = null; nextB = null; nextC = null; isOK = true; return result; } finally { // error happened if (!isOK) { onGoing.setFalse(); } } } }; }; return just(supplier).flatMap(it -> Stream.of(it.get())).onClose(() -> { onGoing.setFalse(); if (holderForAsyncExecutorUsed.isNotNull()) { shutdownTempExecutor(holderForAsyncExecutorUsed.value()); } }); } /** * 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(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @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(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param a * @param b * @param zipFunction * @param bufferedSize * @return */ public static Stream parallelZip(final Stream a, final Stream b, final BiFunction zipFunction, final int bufferedSize) { return parallelZip(iterate(a), iterate(b), zipFunction, bufferedSize).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(..., 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(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param a * @param b * @param c * @param zipFunction * @param bufferedSize * @return */ public static Stream parallelZip(final Stream a, final Stream b, final Stream c, final TriFunction zipFunction, final int bufferedSize) { return parallelZip(iterate(a), iterate(b), iterate(c), zipFunction, bufferedSize).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(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param c * @param zipFunction * @return */ public static Stream parallelZip(final Collection> c, final Function, 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(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param a * @param b * @param c * @param zipFunction * @param bufferedSize * @return */ public static Stream parallelZip(final Collection> c, final Function, R> zipFunction, final int bufferedSize) { 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 parallelZipIterators(iterList, zipFunction, bufferedSize).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(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @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(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param a * @param b * @param valueForNoneA * @param valueForNoneB * @param zipFunction * @param bufferedSize * @return */ public static Stream parallelZip(final Iterable a, final Iterable b, final A valueForNoneA, final B valueForNoneB, final BiFunction zipFunction, final int bufferedSize) { return parallelZip(N.iterate(a), N.iterate(b), valueForNoneA, valueForNoneB, zipFunction, bufferedSize); } /** * 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(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @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(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param a * @param b * @param c * @param valueForNoneA * @param valueForNoneB * @param valueForNoneC * @param zipFunction * @param bufferedSize * @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 bufferedSize) { return parallelZip(N.iterate(a), N.iterate(b), N.iterate(c), valueForNoneA, valueForNoneB, valueForNoneC, zipFunction, bufferedSize); } /** * 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(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param a * @param b * @param valueForNoneA * @param valueForNoneB * @param zipFunction * @return */ 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(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param a * @param b * @param valueForNoneA * @param valueForNoneB * @param zipFunction * @param bufferedSize * @return */ public static Stream parallelZip(final Iterator a, final Iterator b, final A valueForNoneA, final B valueForNoneB, final BiFunction zipFunction, final int bufferedSize) { final AtomicInteger threadCounterA = new AtomicInteger(1); final AtomicInteger threadCounterB = new AtomicInteger(1); final BlockingQueue queueA = new ArrayBlockingQueue<>(bufferedSize); final BlockingQueue queueB = new ArrayBlockingQueue<>(bufferedSize); final Holder eHolder = new Holder<>(); final MutableBoolean onGoing = MutableBoolean.of(true); final Holder holderForAsyncExecutorUsed = new Holder<>(); final Supplier> supplier = () -> { boolean noException = false; try { readToQueue(a, b, DEFAULT_ASYNC_EXECUTOR, threadCounterA, threadCounterB, queueA, queueB, eHolder, onGoing, holderForAsyncExecutorUsed); noException = true; } finally { if (!noException) { onGoing.setFalse(); } } return new BufferedIterator(bufferedSize) { A nextA = null; 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); boolean isOK = false; try { final R result = zipFunction.apply(nextA, nextB); nextA = null; nextB = null; isOK = true; return result; } finally { // error happened if (!isOK) { onGoing.setFalse(); } } } }; }; return just(supplier).flatMap(it -> Stream.of(it.get())).onClose(() -> { onGoing.setFalse(); if (holderForAsyncExecutorUsed.isNotNull()) { shutdownTempExecutor(holderForAsyncExecutorUsed.value()); } }); } /** * 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(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param a * @param b * @param c * @param valueForNoneA * @param valueForNoneB * @param valueForNoneC * @param zipFunction * @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) { 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(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param a * @param b * @param c * @param valueForNoneA * @param valueForNoneB * @param valueForNoneC * @param zipFunction * @param bufferedSize * @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 bufferedSize) { final AtomicInteger threadCounterA = new AtomicInteger(1); final AtomicInteger threadCounterB = new AtomicInteger(1); final AtomicInteger threadCounterC = new AtomicInteger(1); final BlockingQueue queueA = new ArrayBlockingQueue<>(bufferedSize); final BlockingQueue queueB = new ArrayBlockingQueue<>(bufferedSize); final BlockingQueue queueC = new ArrayBlockingQueue<>(bufferedSize); final Holder eHolder = new Holder<>(); final MutableBoolean onGoing = MutableBoolean.of(true); final Holder holderForAsyncExecutorUsed = new Holder<>(); final Supplier> supplier = () -> { 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(); } } return new BufferedIterator(bufferedSize) { A nextA = null; B nextB = null; 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); boolean isOK = false; try { final R result = zipFunction.apply(nextA, nextB, nextC); nextA = null; nextB = null; nextC = null; isOK = true; return result; } finally { // error happened if (!isOK) { onGoing.setFalse(); } } } }; }; return just(supplier).flatMap(it -> Stream.of(it.get())).onClose(() -> { onGoing.setFalse(); if (holderForAsyncExecutorUsed.isNotNull()) { shutdownTempExecutor(holderForAsyncExecutorUsed.value()); } }); } /** * 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(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @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(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param a * @param b * @param valueForNoneA * @param valueForNoneB * @param zipFunction * @param bufferedSize * @return */ public static Stream parallelZip(final Stream a, final Stream b, final A valueForNoneA, final B valueForNoneB, final BiFunction zipFunction, final int bufferedSize) { return parallelZip(iterate(a), iterate(b), valueForNoneA, valueForNoneB, zipFunction, bufferedSize).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(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @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(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param a * @param b * @param c * @param valueForNoneA * @param valueForNoneB * @param valueForNoneC * @param zipFunction * @param bufferedSize * @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 bufferedSize) { return parallelZip(iterate(a), iterate(b), iterate(c), valueForNoneA, valueForNoneB, valueForNoneC, zipFunction, bufferedSize) .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(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param c * @param valuesForNone * @param zipFunction * @return */ public static Stream parallelZip(final Collection> c, final List valuesForNone, Function, 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(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param c * @param valuesForNone * @param zipFunction * @param bufferedSize * @return */ public static Stream parallelZip(final Collection> c, final List valuesForNone, Function, R> zipFunction, final int bufferedSize) { 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 parallelZipIterators(iterList, valuesForNone, zipFunction, bufferedSize).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(..., 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, 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(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param collections * @param zipFunction * @param bufferedSize * @return */ @Beta public static Stream parallelZipIterables(final Collection> collections, final Function, R> zipFunction, final int bufferedSize) { 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, bufferedSize); } /** * 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(..., 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, 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(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param * @param * @param collections * @param valuesForNone * @param zipFunction * @param bufferedSize * @return */ @Beta public static Stream parallelZipIterables(final Collection> collections, final List valuesForNone, Function, R> zipFunction, final int bufferedSize) { 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, bufferedSize); } /** * 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(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param iterators * @param zipFunction * @return */ public static Stream parallelZipIterators(final Collection> iterators, final Function, 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(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param a * @param b * @param iterators * @param zipFunction * @param bufferedSize * @return */ public static Stream parallelZipIterators(final Collection> iterators, final Function, R> zipFunction, final int bufferedSize) { if (N.isNullOrEmpty(iterators)) { return Stream.empty(); } final int len = iterators.size(); final AtomicInteger[] counters = new AtomicInteger[len]; final BlockingQueue[] queues = new ArrayBlockingQueue[len]; final Holder eHolder = new Holder<>(); final MutableBoolean onGoing = MutableBoolean.of(true); final Holder holderForAsyncExecutorUsed = new Holder<>(); final Supplier> supplier = () -> { boolean noException = false; try { readToQueue(iterators, bufferedSize, DEFAULT_ASYNC_EXECUTOR, counters, queues, eHolder, onGoing, holderForAsyncExecutorUsed); noException = true; } finally { if (!noException) { onGoing.setFalse(); } } return new BufferedIterator(bufferedSize) { 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; } } boolean isOK = false; try { R result = zipFunction.apply(Arrays.asList((T[]) next)); next = null; isOK = true; return result; } finally { // error happened if (!isOK) { onGoing.setFalse(); } } } }; }; return just(supplier).flatMap(it -> Stream.of(it.get())).onClose(() -> { onGoing.setFalse(); if (holderForAsyncExecutorUsed.isNotNull()) { shutdownTempExecutor(holderForAsyncExecutorUsed.value()); } }); } /** * 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(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param iterators * @param valuesForNone * @param zipFunction * @return */ public static Stream parallelZipIterators(final Collection> iterators, final List valuesForNone, Function, 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(..., Pair::of/Triple::of/Fn.identity()).parallel().map(zipFunction)... } * * @param iterators * @param valuesForNone * @param zipFunction * @param bufferedSize * @return */ public static Stream parallelZipIterators(final Collection> iterators, final List valuesForNone, final Function, R> zipFunction, final int bufferedSize) { 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 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<>(); final Supplier> supplier = () -> { boolean noException = false; try { readToQueue(iterators, bufferedSize, DEFAULT_ASYNC_EXECUTOR, counters, queues, eHolder, onGoing, holderForAsyncExecutorUsed); noException = true; } finally { if (!noException) { onGoing.setFalse(); } } return new BufferedIterator(bufferedSize) { 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]); } boolean isOK = false; try { R result = zipFunction.apply(Arrays.asList((T[]) next)); next = null; isOK = true; return result; } finally { // error happened if (!isOK) { onGoing.setFalse(); } } } }; }; return just(supplier).flatMap(it -> Stream.of(it.get())).onClose(() -> { onGoing.setFalse(); if (holderForAsyncExecutorUsed.isNotNull()) { shutdownTempExecutor(holderForAsyncExecutorUsed.value()); } }); } // /** // * // * @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 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 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 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 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 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 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 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)); } 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 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 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 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); // 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 - 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 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 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); // 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 - 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); final Iterator iterA = a == null ? ObjIterator. empty() : (Iterator) a; final Iterator iterB = b == null ? ObjIterator. empty() : (Iterator) b; asyncExecutorToUse = execute(asyncExecutorToUse, 2, () -> { 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, 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); 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, () -> { 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, () -> { 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, 1, () -> { 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 bufferedSize, 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); int idx = 0; for (Iterator e : c) { counters[idx] = new AtomicInteger(1); queues[idx] = new ArrayBlockingQueue<>(bufferedSize); final Iterator iter = e; final AtomicInteger count = counters[idx]; final BlockingQueue queue = queues[idx]; asyncExecutorToUse = execute(asyncExecutorToUse, threadNum - 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 static abstract class StreamEx extends Stream { private StreamEx(boolean sorted, Comparator cmp, Collection closeHandlers) { super(sorted, cmp, closeHandlers); // Factory class. } } }