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

com.landawn.abacus.util.stream.BaseStream Maven / Gradle / Ivy

/*
 * Copyright (C) 2024 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.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.function.Function;
import java.util.function.Supplier;

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.TooManyElementsException;
import com.landawn.abacus.util.Difference;
import com.landawn.abacus.util.Duration;
import com.landawn.abacus.util.If.OrElse;
import com.landawn.abacus.util.Immutable;
import com.landawn.abacus.util.ImmutableList;
import com.landawn.abacus.util.ImmutableSet;
import com.landawn.abacus.util.IntList;
import com.landawn.abacus.util.Iterables;
import com.landawn.abacus.util.Joiner;
import com.landawn.abacus.util.Multiset;
import com.landawn.abacus.util.N;
import com.landawn.abacus.util.Percentage;
import com.landawn.abacus.util.RateLimiter;
import com.landawn.abacus.util.Throwables;
import com.landawn.abacus.util.u;
import com.landawn.abacus.util.u.Optional;

import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;

/**
 * This is the base interface for all kinds of streams. 
* The Stream class is an abstract class that represents a stream of elements and supports different kinds of computations.
* The Stream operations are divided into intermediate and terminal operations, and are combined to form stream pipelines.
* *
* The Stream will be automatically closed after a terminal method is called/triggered. * * @param the type of the stream elements * @param the type of array * @param

the type of predicate * @param the type of consumer * @param the type of Optional * @param the type of Indexed element * @param the type of Iterator * @param the type of the stream implementing {@code BaseStream} * @see Stream * @see EntryStream * @see IntStream * @see LongStream * @see DoubleStream * @see com.landawn.abacus.util.Seq * @see Collectors * @see com.landawn.abacus.util.Fn * @see com.landawn.abacus.util.Comparators */ @com.landawn.abacus.annotation.Immutable @LazyEvaluation public interface BaseStream, S extends BaseStream> extends AutoCloseable, Immutable { // extends java.util.stream.BaseStream>, Immutable { // /** // * // * @deprecated Not efficient. // */ // @Deprecated // @Override // default Spliterator spliterator() { // return Spliterators.spliteratorUnknownSize(iterator(), Spliterator.ORDERED | Spliterator.IMMUTABLE); // } // // /** // * @return itself. // * @deprecated No effect. // */ // @Deprecated // @Override // default S unordered() { // return (S) this; // } /** * Returns a stream consisting of the elements of this stream that match the given predicate. * * @param predicate the condition to test the elements of the stream * @return a new Stream consisting of the elements that match the given predicate */ @ParallelSupported @IntermediateOp S filter(P predicate); /** * Returns a stream consisting of the elements of this stream that match the given predicate. * If an element does not match the predicate, the provided action {@code actionOnDroppedItem} is applied to that element. * * This is an intermediate operation. * * @param predicate the condition to test the elements of the stream * @param actionOnDroppedItem the action to perform on the elements that do not match the predicate * This action is only applied to the elements that do not match the predicate and pulled by downstream/terminal operation. * @return a new Stream consisting of the elements that match the given predicate */ @Beta @ParallelSupported @IntermediateOp S filter(P predicate, C actionOnDroppedItem); /** * Keeps the elements until the given predicate returns {@code false}. * The stream should be sorted, which means if x is the first element: {@code predicate.test(x)} returns {@code false}, any element y behind x: {@code predicate.test(y)} should return {@code false}. * * In parallel Streams, the elements after the first element which {@code predicate} returns {@code false} may be tested by predicate too. * *
* For example: *

     * 
     * // For sequential stream:
     * Stream.of(1, 2, 3, 4, 5, 6).takeWhile(it -> it < 5).toList() ===> [1, 2, 3, 4]
     * Stream.of(1, 2, 5, 6, 3, 4).takeWhile(it -> it < 5).toList() ===> [1, 2]
     * Stream.of(5, 6, 1, 2, 3, 4).takeWhile(it -> it < 5).toList() ===> []
     *
     *
     * // For parallel stream:
     * Stream.of(1, 2, 3, 4, 5, 6).parallel().takeWhile(it -> it < 5).toList() ===> [1, 2, 3, 4] // Order could be different since it's in parallel stream.
     * Stream.of(1, 2, 5, 6, 3, 4).parallel().takeWhile(it -> it < 5).toList() ===> [1, 2] // or [1, 2, 3] or [1, 2, 3, 4] // Order could be different since it's in parallel stream.
     * Stream.of(5, 6, 1, 2, 3, 4).parallel().takeWhile(it -> it < 5).toList() ===> any sub set of [1, 2, 3, 4], including [] // Order could be different since it's in parallel stream.
     * 
     * 
* * @param predicate * @return */ @ParallelSupported @IntermediateOp S takeWhile(P predicate); /** * Removes the elements until the given predicate returns {@code false}. * The stream should be sorted, which means if x is the first element: {@code predicate.test(x)} returns {@code true}, any element y behind x: {@code predicate.test(y)} should return {@code true}. * * In parallel Streams, the elements after the first element which {@code predicate} returns {@code false} may be tested by predicate too. * *
* For example: *
     * // For sequential stream:
     * Stream.of(1, 2, 3, 4, 5, 6).dropWhile(it -> it < 4).toList() ===> [4, 5, 6]
     * Stream.of(1, 2, 5, 6, 3, 4).dropWhile(it -> it < 4).toList() ===> [5, 6, 3, 4]
     * Stream.of(5, 6, 1, 2, 3, 4).dropWhile(it -> it < 4).toList() ===> [5, 6, 1, 2, 3, 4]
     *
     *
     * // For parallel stream:
     * Stream.of(1, 2, 3, 4, 5, 6).parallel().dropWhile(it -> it < 4).toList() ===> [4, 5, 6] // Order could be different since it's in parallel stream.
     * Stream.of(1, 2, 5, 6, 3, 4).parallel().dropWhile(it -> it < 4).toList() ===> [5, 6, 4] // or [5, 6, 3, 4] // Order could be different since it's in parallel stream.
     * Stream.of(5, 6, 1, 2, 3, 4).parallel().dropWhile(it -> it < 4).toList() ===> [5, 6] + any sub set of [1, 2, 3, 4] // Order could be different since it's in parallel stream.
     * 
* * @param predicate * @return */ @ParallelSupported @IntermediateOp S dropWhile(P predicate); /** * Removes the elements of this stream until the given predicate returns {@code false}. * The stream should be sorted, which means if x is the first element: {@code predicate.test(x)} returns {@code true}, any element y behind x: {@code predicate.test(y)} should return {@code true}. * * In parallel Streams, the elements after the first element which {@code predicate} returns {@code false} may be tested by predicate too. * * @param predicate the condition to test the elements of the stream * @param actionOnDroppedItem the action to perform on the elements that do not match the predicate * This action is only applied to the elements that do not match the predicate and pulled by downstream/terminal operation. * @return a new Stream consisting of the remaining elements after the elements that do not match the predicate have been removed */ @Beta @ParallelSupported @IntermediateOp S dropWhile(P predicate, C actionOnDroppedItem); /** * Skips elements in the stream until the given predicate returns {@code true}. * The stream should be sorted, which means if x is the first element: {@code predicate.test(x)} returns {@code true}, any element y behind x: {@code predicate.test(y)} should return {@code true}. * * In parallel Streams, the elements after the first element which {@code predicate} returns {@code true} may be tested by predicate too. * * @param predicate the condition to test the elements of the stream * @return a new Stream consisting of the remaining elements after the elements that do not match the predicate have been skipped * @see #dropWhile(Object) */ @Beta @ParallelSupported @IntermediateOp S skipUntil(P predicate); /** * Returns a stream consisting of the distinct elements of this stream. * The elements in the stream are compared for equality using their {@code equals} method. * This operation is stateful and may need to process the entire input before returning. * *
* This method only runs sequentially, even in parallel stream. * * @return A new Stream consisting of the distinct elements of this stream. */ @SequentialOnly @IntermediateOp S distinct(); // /** // * Returns Stream of {@code S} 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 // Stream split(int chunkSize); // // /** // * Returns Stream of {@code PL} 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 // Stream splitToList(int chunkSize); // // /** // * Splits the stream by the specified predicate. // * This stream should be sorted by value which is used to verify the border. // * // *
// * This method only runs sequentially, even in parallel stream. // * // * @implSpec // * {@code Stream.range(0, 7).split(it -> it % 3 == 0) ==> [[0], [1, 2], [3], [4, 5], [6]]} // *
// * {@code Stream.of("a1", "a2", "b1", "b2").split(it -> it.startsWith("a")) ==> [[a1, a2], [b1, b2]]} // * // * @param predicate // * @return // */ // @SequentialOnly // @IntermediateOp // Stream split(final P predicate); // // /** // * Splits the stream by the specified predicate. // * // *
// * This method only runs sequentially, even in parallel stream. // * // * @implSpec // * {@code Stream.range(0, 7).splitToList(it -> it % 3 == 0) ==> [[0], [1, 2], [3], [4, 5], [6]]} // *
// * {@code Stream.of("a1", "a2", "b1", "b2").splitToList(it -> it.startsWith("a")) ==> [[a1, a2], [b1, b2]]} // * // * @param predicate // * @return // */ // @SequentialOnly // @IntermediateOp // Stream splitToList(final P predicate); // // /** // * Splits the stream into two parts at the specified index. // * The element at the specified index will be the first element of the second part // * The first part will be loaded into memory. // * // *
// * This method only runs sequentially, even in parallel stream. // * // * @implSpec // * {@code Stream.range(0, 7).splitAt(3) ==> [[0, 1, 2], [3, 4, 5, 6]]} // * // * // * @param where The index at which to split the stream. // * @return A new Stream consisting of two sub-streams split at the given index. // */ // @SequentialOnly // @IntermediateOp // Stream splitAt(int where); // // /** // * Splits the stream into two pieces at the specified predicate. // * The first piece will be loaded into memory. // * // *
// * This method only runs sequentially, even in parallel stream. // * // *
    //     * 
    //     * Stream.of(1, 3, 2, 4, 2, 5).splitAt(it -> it >= 4).forEach(s -> s.println()); // [1, 3, 2], [4, 2, 5]
    //     * 
    //     * 
// * // * @param where The predicate at which to split the stream. // * @return A new Stream consisting of two sub-streams split at the given predicate. // */ // @SequentialOnly // @IntermediateOp // Stream splitAt(P where); // // /** // * Returns a stream consisting of sub-streams of this stream, each of the same size (the final sub-stream may be smaller). // * The size of each sub-stream is determined by the provided window size. // * // *
// * This method only runs sequentially, even in parallel stream. // * // * @param windowSize The size of each window or sub-stream. // * @return A new Stream consisting of sub-streams of this stream. // * @see #sliding(int, int) // */ // @SequentialOnly // @IntermediateOp // default Stream sliding(final int windowSize) { // return sliding(windowSize, 1); // } // // /** // * Returns a stream consisting of sub-lists of this stream, each of the same size (the final sub-list may be smaller). // * The size of each sub-list is determined by the provided window size. // * // *
// * This method only runs sequentially, even in parallel stream. // * // * @param windowSize The size of each window or sub-list. // * @return A new Stream consisting of sub-lists of this stream. // * @see #sliding(int, int) // */ // @SequentialOnly // @IntermediateOp // default Stream slidingToList(final int windowSize) { // return slidingToList(windowSize, 1); // } // // /** // * Returns a stream consisting of sub-streams of this stream, each of the same size (the final sub-stream may be smaller). // * The size of each sub-stream is determined by the provided window size and increment. // * // *
// * This method only runs sequentially, even in parallel stream. // * // * Stream.of(1, 2, 3, 4, 5, 6, 7, 8).sliding(3, 1).forEach(Stream::println) // *
output:
// * [1, 2, 3]
// * [2, 3, 4]
// * [3, 4, 5]
// * [4, 5, 6]
// * [5, 6, 7]
// * [6, 7, 8]
// * // *
============================================================================
// * Stream.of(1, 2, 3, 4, 5, 6, 7, 8).sliding(3, 3).forEach(Stream::println) // *
output:
// * [1, 2, 3]
// * [4, 5, 6]
// * [7, 8]
// * // *
============================================================================
// * Stream.of(1, 2, 3, 4, 5, 6, 7, 5).sliding(3, 5).forEach(Stream::println) // *
output:
// * [1, 2, 3]
// * [6, 7, 8]
// * // * @param windowSize The size of each window or sub-stream. // * @param increment The step size for the sliding window. // * @return A new Stream consisting of sub-streams of this stream. // */ // @SequentialOnly // @IntermediateOp // Stream sliding(int windowSize, int increment); // // /** // * Returns a stream consisting of sub-lists of this stream, each of the same size (the final sub-list may be smaller). // * The size of each sub-list is determined by the provided window size and increment. // * // *
// * This method only runs sequentially, even in parallel stream. // * // * @param windowSize The size of each window or sub-list. // * @param increment The step size for the sliding window. // * @return A new Stream consisting of sub-lists of this stream. // * @see #sliding(int, int) // */ // @SequentialOnly // @IntermediateOp // Stream slidingToList(int windowSize, int increment); /** * Returns a stream consisting of the elements of this stream that are also present in the specified collection. Occurrences are considered. * The order of the elements in the stream is preserved. * *
* This method only runs sequentially, even in parallel stream. * * @param c The collection to be used for intersection. * @return A new Stream consisting of the elements that are present in both this stream and the specified collection. * @see N#intersection(int[], int[]) * @see N#intersection(Collection, Collection) * @see Collection#retainAll(Collection) */ @SequentialOnly @IntermediateOp S intersection(Collection c); /** * Returns a stream consisting of the elements of this stream that are not present in the specified collection. Occurrences are considered. * The order of the elements in the stream is preserved. * *
* This method only runs sequentially, even in parallel stream. * * @param c The collection to be used for difference. * @return A new Stream consisting of the elements that are present in this stream but not in the specified collection. * @see IntList#difference(IntList) * @see N#difference(Collection, Collection) * @see N#symmetricDifference(Collection, Collection) * @see N#excludeAll(Collection, Collection) * @see N#excludeAllToSet(Collection, Collection) * @see N#removeAll(Collection, Iterable) * @see N#intersection(Collection, Collection) * @see N#commonSet(Collection, Collection) * @see Difference#of(Collection, Collection) */ @SequentialOnly @IntermediateOp S difference(Collection c); /** * Returns a stream consisting of the elements of this stream that are not present in the specified collection and vice versa. Occurrences are considered. * The order of the elements in the stream is preserved. * *
* This method only runs sequentially, even in parallel stream. * * @param c The collection to be used for symmetric difference. * @return A new Stream consisting of the elements that are present in this stream but not in the specified collection and the elements that are present in the specified collection but not in this stream. * @see N#symmetricDifference(int[], int[]) * @see N#excludeAll(Collection, Collection) * @see N#excludeAllToSet(Collection, Collection) * @see N#difference(Collection, Collection) * @see Difference#of(Collection, Collection) * @see Iterables#symmetricDifference(Set, Set) */ @SequentialOnly @IntermediateOp S symmetricDifference(Collection c); /** * Returns a stream consisting of the elements of this stream in reverse order. * All elements will be loaded to memory when this method is called. * *
* This method only runs sequentially, even in parallel stream. * * @return A new Stream consisting of the elements of this stream in reverse order. */ @SequentialOnly @IntermediateOp @TerminalOpTriggered S reversed(); /** * Returns a stream consisting of the elements of this stream rotated by the specified distance. * All elements will be loaded to memory when this method is called. * *
* This method only runs sequentially, even in parallel stream. * * @param distance The distance by which elements are to be rotated. * @return A new Stream consisting of the elements of this stream rotated by the specified distance. */ @SequentialOnly @IntermediateOp @TerminalOpTriggered S rotated(int distance); /** * Returns a stream consisting of the elements of this stream in a shuffled order. * All elements will be loaded to memory when this method is called. * *
* This method only runs sequentially, even in parallel stream. * * @return A new Stream consisting of the elements of this stream in a shuffled order. */ @SequentialOnly @IntermediateOp @TerminalOpTriggered S shuffled(); /** * Returns a stream consisting of the elements of this stream in a shuffled order. The shuffling is determined by the provided Random instance. * All elements will be loaded to memory when this method is called. * *
* This method only runs sequentially, even in parallel stream. * * @param rnd The Random instance used to shuffle the elements. * @return A new Stream consisting of the elements of this stream in a shuffled order. */ @SequentialOnly @IntermediateOp @TerminalOpTriggered S shuffled(Random rnd); /** * Returns a stream consisting of the elements of this stream in sorted order. * All elements will be loaded to memory when this method is called. * *
* This method only runs sequentially, even in parallel stream. * * @return A new Stream consisting of the elements of this stream in sorted order. */ @ParallelSupported @IntermediateOp @TerminalOpTriggered S sorted(); /** * Returns a stream consisting of the elements of this stream in reverse sorted order. * All elements will be loaded to memory when this method is called. * *
* This method only runs sequentially, even in parallel stream. * * @return A new Stream consisting of the elements of this stream in reverse sorted order. */ @ParallelSupported @IntermediateOp @TerminalOpTriggered S reverseSorted(); /** * Returns a stream consisting of the elements of this stream, repeating indefinitely. * Retrieved elements will be saved in memory for next cycle * *
* This method only runs sequentially, even in parallel stream. * * @return A new Stream consisting of the elements of this stream, repeating indefinitely. */ @SequentialOnly @IntermediateOp S cycled(); /** * Returns a stream consisting of the elements of this stream, repeating for the specified number of rounds. * Retrieved elements will be saved in memory for next cycle. * *
* This method only runs sequentially, even in parallel stream. * * @param rounds The number of times the elements of this stream should be repeated. * @return A new Stream consisting of the elements of this stream, repeating for the specified number of rounds. */ @SequentialOnly @IntermediateOp S cycled(long rounds); /** * Returns a stream consisting of the elements of this stream, each paired with its index in the original stream. * The index is zero-based, meaning the first element in the stream will have an index of 0, the second will have an index of 1, and so on. * *
* This method only runs sequentially, even in parallel stream. * * @return A new Stream consisting of Indexed where each Indexed contains an element and its index. */ @SequentialOnly @IntermediateOp Stream indexed(); /** * Skips the first n elements in the stream. * If the stream contains fewer than n elements, an empty stream is returned. * *
* This method only runs sequentially, even in parallel stream. * * @param n The number of elements to skip from the start of the stream. * @return A new Stream consisting of the remaining elements after the first n elements have been skipped. */ @SequentialOnly @IntermediateOp S skip(long n); /** * Skips the first n elements in the stream and applies the provided consumer to each skipped element. * If the stream contains fewer than n elements, an empty stream is returned. * *
* This method only runs sequentially, even in parallel stream. * * @param n The number of elements to skip from the start of the stream. * @param actionOnSkippedItem The consumer to apply to each skipped element. * @return A new Stream consisting of the remaining elements after the first n elements have been skipped and the consumer has been applied. */ @Beta @ParallelSupported @IntermediateOp S skip(long n, C actionOnSkippedItem); /** * Limits the size of the stream to the specified maximum size. * If the stream contains more than maxSize elements, only the first maxSize elements are included in the new stream. * *
* This method only runs sequentially, even in parallel stream. * * @param maxSize The maximum size of the new stream. * @return A new Stream consisting of the first maxSize elements of this stream. */ @SequentialOnly @IntermediateOp S limit(long maxSize); /** * Returns a stream consisting of every 'step'th element of this stream. * This operation is stateful and may need to process the entire input before returning. * For example, if the input stream contains [1, 2, 3, 4, 5, 6] and the step is 2, the output stream will contain [1, 3, 5]. * *
* This method only runs sequentially, even in parallel stream. * * @param step The step size for selecting elements from the stream. * @return A new Stream consisting of every 'step'th element of this stream. */ @SequentialOnly @IntermediateOp S step(long step); /** * Returns a stream with a rate limit applied. The rate limit is specified by the permitsPerSecond parameter. * *
* This method only runs sequentially, even in parallel stream. * * @param permitsPerSecond The rate limit, specified as permits per second. * @return A new Stream with the rate limit applied. * @see RateLimiter#create(double) */ @SequentialOnly @IntermediateOp default S rateLimited(final double permitsPerSecond) { return rateLimited(RateLimiter.create(permitsPerSecond)); } /** * Returns a stream with a rate limit applied. The rate limit is specified by the RateLimiter parameter. * *
* This method only runs sequentially, even in parallel stream. * * @return A new Stream with the rate limit applied. * @see RateLimiter * @see RateLimiter#acquire() */ @SequentialOnly @IntermediateOp S rateLimited(RateLimiter rateLimiter); /** * Delay each element in this {@code Stream} by a given {@link Duration} except the first element. * *
* This method only runs sequentially, even in parallel stream. * * @param duration The duration to delay each element in the stream. * @return A new Stream with the delay applied to each element. */ @SequentialOnly @IntermediateOp S delay(Duration duration); /** * Performs the given action on the elements pulled by downstream/terminal operation. * This is an intermediate operation. * *
* Same as {@code peek}. * * @param action The action to be performed on the elements pulled by downstream/terminal operation * @return A new Stream consisting of the elements of this stream with the provided action applied to each element. * @see #peek(Object) */ @Beta @ParallelSupported @IntermediateOp S onEach(C action); /** * Performs the provided action on the elements pulled by downstream/terminal operation. Mostly it's used for debugging * This is an intermediate operation. * * @param action The action to be performed on the elements pulled by downstream/terminal operation * @return A new Stream consisting of the elements of this stream with the provided action applied to each element. * @see #onEach(Object) */ @ParallelSupported @IntermediateOp default S peek(final C action) { return onEach(action); } /** * Prepends the elements of the provided stream to this stream. * The elements of the provided stream will appear before the elements of this stream in the resulting stream. * * @param stream The stream whose elements should be prepended to this stream. * @return A new Stream consisting of the elements of the provided stream followed by the elements of this stream. */ @SequentialOnly @IntermediateOp S prepend(S stream); /** * Prepends the elements of the provided optional to this stream. * If the optional is present, its elements will appear before the elements of this stream in the resulting stream. * * @param op The optional whose elements should be prepended to this stream. * @return A new Stream consisting of the elements of the provided optional followed by the elements of this stream. */ @SequentialOnly @IntermediateOp S prepend(OT op); /** * Appends the elements of the provided stream to this stream. * The elements of the provided stream will appear after the elements of this stream in the resulting stream. * * @param stream The stream whose elements should be appended to this stream. * @return A new Stream consisting of the elements of this stream followed by the elements of the provided stream. */ @SequentialOnly @IntermediateOp S append(S stream); /** * Appends the elements of the provided optional to this stream. * If the optional is present, its elements will appear after the elements of this stream in the resulting stream. * * @param op The optional whose elements should be appended to this stream. * @return A new Stream consisting of the elements of this stream followed by the elements of the provided optional. */ @SequentialOnly @IntermediateOp S append(OT op); /** * Appends the elements of the provided supplier to this stream if this stream is empty. * If this stream is empty, the elements supplied will appear at the end of this stream in the resulting stream. * * @param supplier The supplier whose elements should be appended to this stream if this stream is empty. * @return A new Stream consisting of the elements of this stream followed by the elements supplied if this stream was empty. * @see #defaultIfEmpty(Supplier) */ @SequentialOnly @IntermediateOp S appendIfEmpty(Supplier supplier); /** * Appends the elements of the provided supplier to this stream if this stream is empty. * If this stream is empty, the elements supplied will appear at the end of this stream in the resulting stream. * *
* Same as {@code appendIfEmpty(Supplier)}. * * @param supplier The supplier whose elements should be appended to this stream if this stream is empty. * @return A new Stream consisting of the elements of this stream followed by the elements supplied if this stream was empty. * @see #appendIfEmpty(Supplier) */ @SequentialOnly @IntermediateOp default S defaultIfEmpty(final Supplier supplier) { return appendIfEmpty(supplier); } /** * Throws a {@code NoSuchElementException} in the executed terminal operation if this {@code Stream} is empty. * * @return The current Stream. */ @SequentialOnly @IntermediateOp S throwIfEmpty(); /** * Throws a custom exception provided by the specified {@code exceptionSupplier} in the executed terminal operation if this {@code Stream} is empty. * * @param exceptionSupplier The supplier of the exception to be thrown if this stream is empty. * @return The current Stream. */ @SequentialOnly @IntermediateOp S throwIfEmpty(Supplier exceptionSupplier); /** * Executes the given action if the stream is empty. * * @param action the action to be executed if the stream is empty * @return the current stream */ @Beta @SequentialOnly @IntermediateOp S ifEmpty(Runnable action); // should be named as doIfEmpty? /** * Joins the elements of this stream into a single String, separated by the specified delimiter. * * @param delimiter The sequence of characters to be used as a delimiter between each element in the resulting String. * @return A String consisting of the elements of this stream, separated by the specified delimiter. */ @SequentialOnly @TerminalOp default String join(final CharSequence delimiter) { return join(delimiter, "", ""); } /** * Joins the elements of this stream into a single String, separated by the specified delimiter, prefix, and suffix. * * @param delimiter The sequence of characters to be used as a delimiter between each element in the resulting String. * @param prefix The sequence of characters to be added at the beginning of the resulting String. * @param suffix The sequence of characters to be added at the end of the resulting String. * @return A String consisting of the elements of this stream, separated by the specified delimiter, and surrounded by the specified prefix and suffix. */ @SequentialOnly @TerminalOp String join(final CharSequence delimiter, final CharSequence prefix, final CharSequence suffix); // /** // * // * @param joiner // * @return // * @throws E // * @deprecated replaced by {@code joinTo(Joiner)} // */ // @Deprecated // @TerminalOp // default String join(final Joiner joiner) { // return joinTo(joiner).toString(); // } /** * Joins the elements of this stream into a single String using the provided Joiner. * The Joiner specifies the delimiter, prefix, and suffix to be used for joining. * * @param joiner The Joiner specifying how to join the elements of the stream. * @return The provided Joiner after it has been used to join the elements of the stream. * @see Joiner */ @SequentialOnly @TerminalOp Joiner joinTo(final Joiner joiner); /** * Calculates and returns the percentiles of the elements in this stream. * All elements will be loaded into memory and sorted if not yet. * The returned map contains the percentile values as keys and the corresponding elements as values. * * @return An Optional containing a Map of Percentages to elements if the stream is not empty, otherwise an empty Optional. * @see N#percentiles(int[]) */ @SequentialOnly @TerminalOp Optional> percentiles(); /** * Counts the number of elements in the stream. * * @return The count of elements in the stream. */ @SequentialOnly @TerminalOp long count(); /** * Returns the first element of the stream. * * @return An Optional containing the first element of the stream if it exists, otherwise an empty Optional. */ @SequentialOnly @TerminalOp OT first(); /** * Returns the last element of the stream. * * @return An Optional containing the last element of the stream if it exists, otherwise an empty Optional. */ @SequentialOnly @TerminalOp OT last(); /** * Returns the element at the specified position in this stream. * The position is zero-based, meaning the first element in the stream has a position of 0, the second has a position of 1, and so on. * * @param position The position of the element to return. * @return An Optional containing the element at the specified position in this stream if it exists, otherwise an empty Optional. */ @Beta @SequentialOnly @TerminalOp OT elementAt(long position); /** * Returns an {@code Optional} containing the only element of this stream if it contains exactly one element, or an empty {@code Optional} if the stream is empty * If the stream contains more than one element, an exception is thrown. * *
* This is a terminal operation and will close the stream. * * @return an {@code Optional} containing the only element of this stream, or an empty {@code Optional} if the stream is empty * @throws TooManyElementsException if the stream contains more than one element */ @SequentialOnly @TerminalOp OT onlyOne() throws TooManyElementsException; /** * Converts the elements of this stream into an array. * * @return An array containing the elements of this stream. */ @SequentialOnly @TerminalOp A toArray(); /** * Converts the elements of this stream into a List. * * @return A modifiable List containing the elements of this stream. */ @SequentialOnly @TerminalOp List toList(); /** * Converts the elements of this stream into a Set. * * @return A modifiable Set containing the unique elements of this stream. */ @SequentialOnly @TerminalOp Set toSet(); /** * Converts the elements of this stream into an ImmutableList. * * @return An ImmutableList containing the elements of this stream. */ @SequentialOnly @TerminalOp ImmutableList toImmutableList(); /** * Converts the elements of this stream into an ImmutableSet. * * @return An ImmutableSet containing the unique elements of this stream. */ @SequentialOnly @TerminalOp ImmutableSet toImmutableSet(); /** * Converts the elements of this stream into a Collection. * The type of Collection is determined by the provided supplier. * * @param The type of Collection to create. * @param supplier A supplier function that provides a new, empty Collection of the desired type. * @return A Collection of the desired type containing the elements of this stream. */ @SequentialOnly @TerminalOp > CC toCollection(Supplier supplier); /** * Converts the elements of this stream into a Multiset. * * @return A Multiset containing the elements of this stream. */ @SequentialOnly @TerminalOp Multiset toMultiset(); /** * Converts the elements of this stream into a Multiset. * The type of Multiset is determined by the provided supplier. * * @param supplier A supplier function that provides a new, empty Multiset of the desired type. * @return A Multiset of the desired type containing the elements of this stream. */ @SequentialOnly @TerminalOp Multiset toMultiset(Supplier> supplier); //NOSONAR /** * Prints the stream to the standard output. * Be caution to use it when the stream is large. * * @implNote it's equivalent to {@code System.out.println(stream.join(", ", "[", "]"))} * *
* This is a terminal operation and will close the stream. */ @Beta @SequentialOnly @TerminalOp void println(); /** * Returns an iterator for the elements of this stream. * *
* Remember to close this Stream after the iteration is done, if needed. * * @return An iterator for the elements of this stream. * @deprecated ? may cause memory/resource leak if forget to close this {@code Stream} */ @SequentialOnly @Deprecated ITER iterator(); /** * Checks if the stream is running in parallel mode. * * @return {@code true} if the stream is running in parallel mode, {@code false} otherwise. */ boolean isParallel(); /** * Switches the stream to sequential mode. * In sequential mode, the operations on the stream are performed in the order of the elements in the stream. * This is an intermediate operation. * * @return A new Stream that is identical to this stream, but in sequential mode. */ @SequentialOnly @IntermediateOp S sequential(); /** * Switches the stream to parallel mode. * This is an intermediate operation. * *
* Consider using {@code sps(int, Function)} if only next operation need to be parallelized. For example: *
     * stream.parallel(maxThreadNum).map(f).filter(p)...;
     *
     * // Replace above line of code with "sps" if only "f" need to be parallelized. And "p" is fast enough to be executed in sequential Stream.
     * stream.sps(maxThreadNum, s -> s.map(f)).filter(p)...;
     * // Or switch the stream back sequential stream by {@code sequential()}.
     * stream.parallel(maxThreadNum).map(f).sequential().filter(p)...;
     * 
* * When to use parallel Streams? *
*
     * 
     * Profiler.run(1, 1, 3, "sequential", () -> Stream.of(list).operation(F)...).printResult();
     * Profiler.run(1, 1, 3, "parallel", () -> Stream.of(list).parallel().operation(F)...).printResult();
     * 
     * 
* * Here is a sample performance test with computer: CPU Intel i7-3520M 4-cores 2.9 GHz, JDK 1.8.0_101, Windows 7: * *
     * 
     *
     *      public void test_perf() {
     *         final String[] strs = new String[10_000];
     *         N.fill(strs, Strings.uuid());
     *
     *         final int m = 10;
     *         final Function<String, Long> mapper = str -> {
     *             long result = 0;
     *             for (int i = 0; i < m; i++) {
     *                 result += N.sum(str.toCharArray()) + 1;
     *             }
     *             return result;
     *         };
     *
     *         final MutableLong sum = MutableLong.of(0);
     *
     *         for (int i = 0, len = strs.length; i < len; i++) {
     *             sum.add(mapper.apply(strs[i]));
     *         }
     *
     *         final int threadNum = 1, loopNum = 100, roundNum = 3;
     *
     *         Profiler.run(threadNum, loopNum, roundNum, "For Loop", () -> {
     *             long result = 0;
     *             for (int i = 0, len = strs.length; i < len; i++) {
     *                 result += mapper.apply(strs[i]);
     *             }
     *             assertEquals(sum.longValue(), result);
     *         }).printResult();
     *
     *         Profiler.run(threadNum, loopNum, roundNum, "JDK Sequential",
     *                 () -> assertEquals(sum.longValue(), java.util.stream.Stream.of(strs).map(mapper).mapToLong(e -> e).sum())).printResult();
     *
     *         Profiler.run(threadNum, loopNum, roundNum, "JDK Parallel",
     *                 () -> assertEquals(sum.longValue(), java.util.stream.Stream.of(strs).parallel().map(mapper).mapToLong(e -> e).sum())).printResult();
     *
     *         Profiler.run(threadNum, loopNum, roundNum, "Abacus Sequential", () -> assertEquals(sum.longValue(), Stream.of(strs).map(mapper).mapToLong(e -> e).sum()))
     *                 .printResult();
     *
     *         Profiler.run(threadNum, loopNum, roundNum, "Abacus Parallel",
     *                 () -> assertEquals(sum.longValue(), Stream.of(strs).parallel().map(mapper).mapToLong(e -> e).sum())).printResult();
     *
     *         Profiler.run(threadNum, loopNum, roundNum, "Abacus Parallel by chunk", () -> assertEquals(sum.longValue(),
     *                 Stream.of(strs).splitToList(100).parallel().map(it -> N.sumLong(it, e -> mapper.apply(e))).mapToLong(e -> e).sum())).printResult();
     *      }
     * 
     * 
* And test result: Unit is milliseconds. N(the number of elements) is 10_000, Q(cost per element of F, the per-element function (usually a lambda), here is {@code mapper}) is calculated by: value of 'For loop' / N(10_000). * * * * * * * * *
m = 1 m = 10m = 50m = 100m = 500m = 1000
Q 0.000020.00020.0010.0020.010.02
For Loop0.232.31122110219
JDK Sequential0.282.31122114212
JDK Parallel0.221.361266122
Abacus Sequential0.321122112212
Abacus Parallel1111111677128
* * Comparison: *
    *
  • Again, do NOT and should NOT use parallel Streams if you don't have any performance problem with sequential Streams, because using parallel Streams has extra cost.
  • *
  • Again, consider using parallel Streams only when N(the number of elements) * Q(cost per element of F, the per-element function (usually a lambda)) is big enough.
  • *
  • The implementation of parallel Streams in Abacus is more than 10 times, slower than parallel Streams in JDK when Q is tiny(here is less than 0.0002 milliseconds by the test):
  • *
      *
    • The implementation of parallel Streams in JDK 8 still can beat the sequential/for loop when Q is tiny(Here is 0.00002 milliseconds by the test). * That's amazing, considering the extra cost brought by parallel computation. It's well done.
    • *
    • The implementation of parallel Streams in Abacus is pretty simple and straight forward. * The extra cost(starting threads/synchronization/queue...) brought by parallel Streams in Abacus is too bigger to tiny Q(Here is less than 0.001 milliseconds by the test). * But it starts to be faster than sequential Streams when Q is big enough(Here is 0.001 milliseconds by the test) and starts to catch the parallel Streams in JDK when Q is bigger(Here is 0.01 milliseconds by the test).
    • *
    • Consider using the parallel Streams in Abacus when Q is big enough, specially when IO involved in F. * Because one IO operation(e.g. DB/web service request..., Reading/Writing file...) usually takes 1 to 1000 milliseconds, or even longer. * By the parallel Streams APIs in Abacus, it's very simple to specify max thread numbers. Sometimes, it's much faster to execute IO/Network requests with a bit more threads. * It's fair to say that the parallel Streams in Abacus is high efficient, may same as or faster than the parallel Streams in JDK when Q is big enough, except F is heavy cpu-used operation. * Usually, the Q is big enough to consider using parallel Stream is because IO/Network is involved in F.
    • *
    *
  • JDK 7 is supported by the Streams in Abacus. It's perfect to work with retrolambda on Android
  • *
  • All primitive types are supported by Stream APIs in Abacus except boolean
  • *
* *

* A bit more about Lambdas/Stream APIs, you may hear that Lambdas/Stream APIs is 5 time slower than imperative programming. * It's {@code true} when Q and F is VERY, VERY tiny, like f = (int a, int b) -> a + b;. * But if we look into the samples in the article and think about it: it just takes less than 1 millisecond to get the max value in 100k numbers. * There is potential performance issue only if the "get the max value in 100K numbers" call many, many times in your API or single request. * Otherwise, the difference between 0.1 milliseconds to 0.5 milliseconds can be totally ignored. * Usually we meet performance issue only if Q and F is big enough. However, the performance of Lambdas/Streams APIs is closed to for loop when Q and F is big enough. * No matter in which scenario, We don't need and should not concern the performance of Lambdas/Stream APIs. * *

* Although it's in parallel Streams, it doesn't mean all the methods are executed in parallel. * Because the sequential way is as fast, or even faster than the parallel way for some methods, or is pretty difficult, if not possible, to implement the method by parallel approach. * Methods annotated with {@code @SequentialOnly} are executed in sequential way even in parallel Streams. for example: *

* splitXXX/splitAt/splitBy/slidingXXX/collapse, distinct, reverse, rotate, shuffle, indexed, cached, top, kthLargest, count, toArray, toList, toList, toSet, toMultiset... * * @return * @see #sps(Function) * @see #sps(int, Function) * @see #parallel(int) * @see #parallel(Executor) * @see #parallel(int, Executor) * @see com.landawn.abacus.util.Profiler#run(int, int, int, com.landawn.abacus.util.Throwables.Runnable) * @see Understanding Parallel Stream Performance in Java SE 8 * @see When to Use a Parallel Stream in Java * @see When to use parallel Streams */ @SequentialOnly @IntermediateOp S parallel(); /** * Switches the stream to parallel mode. * This is an intermediate operation. * *
* Consider using {@code sps(int, Function)} if only next operation need to be parallelized. For example: *
     * stream.parallel(maxThreadNum).map(f).filter(p)...;
     *
     * // Replace above line of code with "sps" if only "f" need to be parallelized. And "p" is fast enough to be executed in sequential Stream.
     * stream.sps(maxThreadNum, s -> s.map(f)).filter(p)...;
     * // Or switch the stream back sequential stream by {@code sequential()}.
     * stream.parallel(maxThreadNum).map(f).sequential().filter(p)...;
     * 
* * @param maxThreadNum if the specified value is bigger than the maximum allowed thread number per operation ({@code min(64, cpu_cores * 8)}), maximum allowed thread number per operation will be used. * To parallelize this Stream with thread number bigger than {@code min(64, cpu_cores * 8)}, please specified {@code executor} by calling {@link #parallel(int, Executor)} or {@link #parallel(ParallelSettings)} * @return * @see #sps(Function) * @see #sps(int, Function) * @see #parallel() * @see #parallel(Executor) * @see #parallel(int, Executor) */ @SequentialOnly @IntermediateOp S parallel(int maxThreadNum); /** * Switches the stream to parallel mode. * This is an intermediate operation. * *
* Consider using {@code sps(int, Function)} if only next operation need to be parallelized. For example: *
     * stream.parallel(maxThreadNum).map(f).filter(p)...;
     *
     * // Replace above line of code with "sps" if only "f" need to be parallelized. And "p" is fast enough to be executed in sequential Stream.
     * stream.sps(maxThreadNum, s -> s.map(f)).filter(p)...;
     * // Or switch the stream back sequential stream by {@code sequential()}.
     * stream.parallel(maxThreadNum).map(f).sequential().filter(p)...;
     * 
* * @param executor call could be hanged if this executor is created by {@code Executors.newVirtualThreadPerTaskExecutor()} and used by multiple calls in this stream. * @return * @see #sps(Function) * @see #sps(int, Function) * @see #parallel() * @see #parallel(int) * @see #parallel(int, Executor) */ @SequentialOnly @IntermediateOp S parallel(Executor executor); /** * Switches the stream to parallel mode. * This is an intermediate operation. * *
* Consider using {@code sps(int, Function)} if only next operation need to be parallelized. For example: *
     * stream.parallel(maxThreadNum).map(f).filter(p)...;
     *
     * // Replace above line of code with "sps" if only "f" need to be parallelized. And "p" is fast enough to be executed in sequential Stream.
     * stream.sps(maxThreadNum, s -> s.map(f)).filter(p)...;
     * // Or switch the stream back sequential stream by {@code sequential()}.
     * stream.parallel(maxThreadNum).map(f).sequential().filter(p)...;
     * 
* * @param maxThreadNum if the specified value is bigger than the maximum allowed thread number per operation ({@code min(64, cpu_cores * 8)}) and {@code executor} is not specified with a {@code non-null} value, maximum allowed thread number per operation will be used. * To parallelize this Stream with thread number bigger than {@code min(64, cpu_cores * 8)}, please specify {@code executor} with a {@code non-null} value. * @param executor call could be hanged if this executor is created by {@code Executors.newVirtualThreadPerTaskExecutor()} and used by multiple calls in this stream. * @return * @see #sps(Function) * @see #sps(int, Function) * @see #parallel() * @see #parallel() * @see #parallel(int) * @see #parallel(Executor) */ @SequentialOnly @IntermediateOp S parallel(int maxThreadNum, Executor executor); // /** // * Switches the stream to parallel mode. // * This is an intermediate operation. // * // *
// * Consider using {@code sps(int, Function)} if only next operation need to be parallelized. For example: // *
    //     * stream.parallel(maxThreadNum).map(f).filter(p)...;
    //     *
    //     * // Replace above line of code with "sps" if only "f" need to be parallelized. And "p" is fast enough to be executed in sequential Stream.
    //     * stream.sps(maxThreadNum, s -> s.map(f)).filter(p)...;
    //     * // Or switch the stream back sequential stream by {@code sequential()}.
    //     * stream.parallel(maxThreadNum).map(f).sequential().filter(p)...;
    //     * 
// * // * @param splitor // * @return // * @see #sps(Function) // * @see #sps(int, Function) // * @see #parallel() // * @see #parallel(Executor) // * @see #parallel(int, Executor) // */ // @SequentialOnly // @IntermediateOp // S parallel(Splitor splitor); // // /** // * Switches the stream to parallel mode. // * This is an intermediate operation. // * // *
// * Consider using {@code sps(int, Function)} if only next operation need to be parallelized. For example: // *
    //     * stream.parallel(maxThreadNum).map(f).filter(p)...;
    //     *
    //     * // Replace above line of code with "sps" if only "f" need to be parallelized. And "p" is fast enough to be executed in sequential Stream.
    //     * stream.sps(maxThreadNum, s -> s.map(f)).filter(p)...;
    //     * // Or switch the stream back sequential stream by {@code sequential()}.
    //     * stream.parallel(maxThreadNum).map(f).sequential().filter(p)...;
    //     * 
// * // * @param maxThreadNum if the specified value is bigger than the maximum allowed thread number per operation ({@code min(64, cpu_cores * 8)}), maximum allowed thread number per operation will be used. // * To parallelize this Stream with thread number bigger than {@code min(64, cpu_cores * 8)}, please specify {@code executor} by calling {@link #parallel(int, Executor)} or {@link #parallel(int, Splitor, Executor)} or {@link #parallel(ParallelSettings)} // * @param splitor // * @return // * @see #sps(Function) // * @see #sps(int, Function) // * @see #parallel() // * @see #parallel(Executor) // * @see #parallel(int, Executor) // * @see MergeResult // * @see com.landawn.abacus.util.Profiler#run(int, int, int, com.landawn.abacus.util.Throwables.Runnable) // * @see Understanding Parallel Stream Performance in Java SE 8 // * @see When to Use a Parallel Stream in Java // * @see When to use parallel Streams // */ // @SequentialOnly // @IntermediateOp // S parallel(int maxThreadNum, Splitor splitor); // // /** // * Switches the stream to parallel mode. // * This is an intermediate operation. // * // *
// * Consider using {@code sps(int, Function)} if only next operation need to be parallelized. For example: // *
    //     * stream.parallel(maxThreadNum).map(f).filter(p)...;
    //     *
    //     * // Replace above line of code with "sps" if only "f" need to be parallelized. And "p" is fast enough to be executed in sequential Stream.
    //     * stream.sps(maxThreadNum, s -> s.map(f)).filter(p)...;
    //     * // Or switch the stream back sequential stream by {@code sequential()}.
    //     * stream.parallel(maxThreadNum).map(f).sequential().filter(p)...;
    //     * 
// * // * // * @param maxThreadNum if the specified value is bigger than the maximum allowed thread number per operation ({@code min(64, cpu_cores * 8)}) and {@code executor} is not specified with a {@code non-null} value, maximum allowed thread number per operation will be used. // * To parallelize this Stream with thread number bigger than {@code min(64, cpu_cores * 8)}, please specify {@code executor} with a {@code non-null} value. // * @param splitor // * @param executor call could be hanged if this executor is created by {@code Executors.newVirtualThreadPerTaskExecutor()} and used by multiple calls in this stream. // * @return // * @see #sps(Function) // * @see #sps(int, Function) // * @see #parallel() // */ // @SequentialOnly // @IntermediateOp // S parallel(int maxThreadNum, Splitor splitor, Executor executor); // /** // * Java 19 or above is required. // * // * @param maxThreadNum // * @param withVirtualThread // * @return // * @see #parallel(int, int) // * @see Executors#newVirtualThreadPerTaskExecutor() // * @see JEP 425: Virtual Threads // * @see Java Virtual Threads: Millions of Threads Within Grasp // */ // @Beta // @SequentialOnly // @IntermediateOp // S parallel(int maxThreadNum, boolean withVirtualThread); // // /** // * Virtual threads executed by each instance of {@code ExecutorService} created by {@code Executors.newVirtualThreadPerTaskExecutor()} will be {@code maxThreadNum / executorNumForVirtualThread}. // *
// * Probably {@code parallel(maxThreadNum, true)} will be enough for a lot of long delay and light requests(e.g. Web/DB requests). // * // *
// * Java 19 or above is required. // * // * @param maxThreadNum // * @param executorNumForVirtualThread // * @return // * @see #parallel(int, boolean) // * @see Executors#newVirtualThreadPerTaskExecutor() // * @see JEP 425: Virtual Threads // * @see Java Virtual Threads: Millions of Threads Within Grasp // */ // @Beta // @SequentialOnly // @IntermediateOp // S parallel(int maxThreadNum, int executorNumForVirtualThread); /** * Switches the stream to parallel mode. * This is an intermediate operation. * *
* Consider using {@code sps(int, Function)} if only next operation need to be parallelized. For example: *
     * stream.parallel(maxThreadNum).map(f).filter(p)...;
     *
     * // Replace above line of code with "sps" if only "f" need to be parallelized. And "p" is fast enough to be executed in sequential Stream.
     * stream.sps(maxThreadNum, s -> s.map(f)).filter(p)...;
     * // Or switch the stream back sequential stream by {@code sequential()}.
     * stream.parallel(maxThreadNum).map(f).sequential().filter(p)...;
     * 
* * @param ps * @return * @see #sps(Function) * @see #sps(int, Function) * @see #parallel() * @see #parallel(int) * @see #parallel(Executor) * @see #parallel(int, Executor) */ @Beta @SequentialOnly @IntermediateOp S parallel(ParallelSettings ps); /** * Temporarily switch the stream to parallel stream for operation {@code ops} and then switch back to sequence stream. *
* {@code stream().parallel().ops(map/filter/...).sequence()} * * @param * @param ops * @return * @see #sps(int, Function) * @see #sps(int, Executor, Function) * @see #parallel() * @see #parallel(Executor) * @see #parallel(int, Executor) */ @Beta @SequentialOnly @IntermediateOp @SuppressWarnings("rawtypes") SS sps(Function ops); /** * Temporarily switch the stream to parallel stream for operation {@code ops} and then switch back to sequence stream. *
* {@code stream().parallel(maxThreadNum).ops(map/filter/...).sequence()} * * @param * @param maxThreadNum * @param ops * @return * @see #sps(Function) * @see #sps(int, Executor, Function) * @see #parallel() * @see #parallel(Executor) * @see #parallel(int, Executor) */ @Beta @SequentialOnly @IntermediateOp @SuppressWarnings("rawtypes") SS sps(int maxThreadNum, Function ops); /** * Temporarily switch the stream to parallel stream for operation {@code ops} and then switch back to sequence stream. *
* {@code stream().parallel(maxThreadNum).ops(map/filter/...).sequence()} * * @param * @param maxThreadNum * @param executor * @param ops * @return * @see #sps(Function) * @see #sps(int, Function) * @see #parallel() * @see #parallel(Executor) * @see #parallel(int, Executor) */ @Beta @SequentialOnly @IntermediateOp @SuppressWarnings("rawtypes") SS sps(int maxThreadNum, Executor executor, Function ops); // @Beta // @SequentialOnly // @IntermediateOp // @SuppressWarnings("rawtypes") // SS sps(int maxThreadNum, boolean withVirtualThread, Function ops); // // @Beta // @SequentialOnly // @IntermediateOp // @SuppressWarnings("rawtypes") // SS sps(int maxThreadNum, int executorNumForVirtualThread, Function ops); // /** // * Temporarily switch the stream to parallel stream for operation {@code ops} and then switch back to sequence stream. // *
// * {@code stream().parallel(ps).ops(map/filter/...).sequence()} // * // * @param // * @param ps // * @param ops // * @return // */ // @Beta // @SequentialOnly // @IntermediateOp // @SuppressWarnings("rawtypes") // SS sps(ParallelSettings ps, Function ops); // /** // * Returns a new sequential {@code SS} by apply {@code thisStream.parallel()} to the specified {@code func}. // * It's equal to: // *
    //     * 
    //     * thisStream.parallel().(action by func).sequential();
    //     * 
    //     * 
// * // * @param func // * @return // * @deprecated // */ // @Deprecated // > SS parallelOnly(Function func); // // /** // * Returns a new sequential {@code SS} by apply {@code thisStream.parallel(maxThreadNum)} to the specified {@code func}. // * It's equal to: // *
    //     * 
    //     * thisStream.parallel(maxThreadNum).(action by func).sequential();
    //     * 
    //     * 
// * // * @param maxThreadNum // * @param func // * @return // * @deprecated // */ // @Deprecated // > SS parallelOnly(int maxThreadNum, Function func); // // /** // * Returns a new sequential {@code S} by apply {@code thisStream.parallel(maxThreadNum, executor)} to the specified {@code func}. // * // *
    //     * 
    //     * thisStream.parallel(maxThreadNum, executor).(action by func).sequential();
    //     * 
    //     * 
// * // * @param maxThreadNum // * @param executor should be able to execute {@code maxThreadNum} * {@code following up operations} in parallel. // * @return // * @deprecated // */ // @Deprecated // > SS parallelOnly(int maxThreadNum, Executor executor, Function func); // /** // * Return the underlying maxThreadNum if the stream is parallel, otherwise 1 is returned. // * // * @return // */ // int maxThreadNum(); // /** // * Returns a parallel stream with the specified maxThreadNum . Or return // * itself, either because the stream was already parallel with same maxThreadNum, or because // * it's a sequential stream. // * // * @param maxThreadNum // * @return // * @deprecated // */ // @Deprecated // S maxThreadNum(int maxThreadNum); // /** // * Return the underlying splitor if the stream is parallel, otherwise the default value splitor.ITERATOR is returned. // * // * @return // */ // Splitor splitor(); // /** // * Returns a parallel stream with the specified splitor . Or return // * itself, either because the stream was already parallel with same splitor, or because // * it's a sequential stream. // * // * @param splitor // * @return // * @deprecated // */ // @Deprecated // S splitor(Splitor splitor); /** * Temporarily switches the stream to a sequential stream for the operation {@code ops} and then switches it back to a parallel stream with same {@code maxThreadNum/splitor/asyncExecutor} * This method is useful for performing a specific operation sequentially while keeping the rest of the stream operations parallel. *
* @implSpec it's same as {@code stream().sequence().ops(map/filter/...).parallel(sameMaxThreadNum, sameSplitor, sameAsyncExe} * * @param The type of the new stream. * @param ops The operation function to apply to the stream. * @return A new Stream that has been operated upon sequentially using the provided operation function. * @see #parallel() * @see #parallel(Executor) * @see #parallel(int, Executor) */ @Beta @SequentialOnly @IntermediateOp @SuppressWarnings("rawtypes") SS psp(Function ops); /** * Transforms the current stream into a new stream using the provided transformation function. * This method is useful for performing complex transformations that cannot be achieved with the standard stream operations. * *
*
* {@code Stream/ByteStream...DoubleStream.defer(Supplier)} can be used to avoid eager loading by terminal operations invoked in {@code transfer}. For example: * *
     * 
     *     stream.transform(s -> Stream/ByteStream...DoubleStream.defer(() -> s.(..).someTerminalOperation(...)));
     * 
     * 
* * @param The type of the new stream. * @param transfer The transformation function that takes the current stream and returns a new stream. * @return A new stream transformed by the provided function. * @throws IllegalArgumentException if the provided function is {@code null}. * @throws IllegalStateException if the stream has already been operated upon or closed. */ @Beta @SequentialOnly @IntermediateOp @SuppressWarnings("rawtypes") RS transform(Function transfer); //NOSONAR /** * Transforms the current stream into a new stream using the provided transformation function. * This method is deprecated and replaced by {@link #transform(Function)}. * * @param The type of the new stream. * @param transfer The transformation function that takes the current stream and returns a new stream. * @return A new stream transformed by the provided function. * @throws IllegalArgumentException if the provided function is {@code null}. * @throws IllegalStateException if the stream has already been operated upon or closed. * @see #transform(Function) */ @Beta @SequentialOnly @IntermediateOp @SuppressWarnings("rawtypes") default RS __(final Function transfer) { //NOSONAR return transform(transfer); } /** * Applies the provided function to the stream if it is not empty. * This is a terminal operation, meaning that the stream will be closed after this operation. * * @param The return type of the function. * @param The type of exception that the function can throw. * @param func The function to be applied to the stream. * @return An Optional containing the result of the function if the stream is not empty, or an empty Optional if the stream is empty. * @throws E if the function throws an exception. */ @SequentialOnly @TerminalOp u.Optional applyIfNotEmpty(Throwables.Function func) throws E; /** * Applies the provided consumer to the stream if it is not empty. * This is a terminal operation, meaning that the stream will be closed after this operation. * * @param The type of exception that the consumer can throw. * @param action The consumer to be applied to the stream. * @return An OrElse instance which can be used to perform further actions if the stream is empty. * @throws E if the consumer throws an exception. */ @SequentialOnly @TerminalOp OrElse acceptIfNotEmpty(Throwables.Consumer action) throws E; /** * Registers a close handler to be invoked when the stream is closed. * This method can be called multiple times to register multiple handlers. * Handlers are invoked in the order they were added, first-added, first-invoked. * * @param closeHandler The Runnable to be invoked when the stream is closed. * @return A new stream with the close handler registered. * @throws IllegalArgumentException if the provided closeHandler is {@code null}. * @throws IllegalStateException if the stream has already been operated upon or closed. */ @SequentialOnly @IntermediateOp S onClose(Runnable closeHandler); /** * Closes the stream, releasing any system resources associated with it. * If the stream is already closed then invoking this method has no effect. * As per the AutoCloseable contract, close methods are idempotent. * Streams are automatically closed when the source data is exhausted and are * therefore not required to be closed manually. * It is recommended to use try-with-resources or call close when done * to ensure correct resource management. */ @Override void close(); /** * Usually, elements will be fetched and processed by parallel threads one by one. * *
     * synchronized (elements) {
     *    if (elements.hasNext()) {
     *       next = elements.next();
     *    }
     * }
     *
     * // Do something with next...
     * 
* * {@code Splitor.ARRAY} only works when stream elements are stored in an array. * The array will be equally split into slices based on thread number for each thread: * *
     * int sliceSize = (toIndex - fromIndex) / threadNum + ((toIndex - fromIndex) % threadNum == 0 ? 0 : 1);
     * 
* * If stream elements are not stored in an array, {@code Splitor.ARRAY} just works as same as how {@code Splitor.ITERATOR} works. * *
*
* * If you want to customize the chunk size for each thread, try {@code stream.split(chunkSize)} *
     * stream.split(chunkSize).parallel(...).map/filter/flatMap...(sliceList -> // do whatever you want to do);
     * // Or
     * stream.sps(maxThreadNum, chunkSize, op)
     * 
* * @see Stream#sps(Function) * @see Stream#sps(int, Function) * @see Stream#sps(int, int, Function) */ enum Splitor { /** * Elements will be fetched and processed by parallel threads one by one. * *
         * synchronized (elements) {
         *    if (elements.hasNext()) {
         *       next = elements.next();
         *    }
         * }
         *
         * // Do something with next...
         * 
* * @see Stream#sps(Function) * @see Stream#sps(int, Function) * @see Stream#sps(int, int, Function) */ ITERATOR, /** * {@code Splitor.ARRAY} only works when stream elements are stored in an array. * The array will be equally split into slices based on thread number for each thread: * *
         * int sliceSize = (toIndex - fromIndex) / threadNum + ((toIndex - fromIndex) % threadNum == 0 ? 0 : 1);
         * 
* * If stream elements are not stored in an array, {@code Splitor.ARRAY} just works as same as how {@code Splitor.ITERATOR} works. * * @see Stream#sps(Function) * @see Stream#sps(int, Function) * @see Stream#sps(int, int, Function) */ ARRAY } @Data @Accessors(fluent = true) @EqualsAndHashCode(callSuper = false) final class ParallelSettings { private int maxThreadNum; /** * @deprecated Not supported yet. */ @Deprecated private int executorNumForVirtualThread; // Not supported yet. /** * @deprecated not sure if it's necessary. */ @Deprecated private Splitor splitor; private Executor executor; // private boolean cancelUncompletedThreads = false; @Beta public static final class PS { private PS() { // utility class; } /** * * * @param maxThreadNum * @return */ public static ParallelSettings create(final int maxThreadNum) { return new ParallelSettings().maxThreadNum(maxThreadNum); } /** * * * @param splitor * @return */ public static ParallelSettings create(final Splitor splitor) { return new ParallelSettings().splitor(splitor); } /** * * * @param executor * @return */ public static ParallelSettings create(final Executor executor) { return new ParallelSettings().executor(executor); } /** * * * @param maxThreadNum * @param splitor * @return */ public static ParallelSettings create(final int maxThreadNum, final Splitor splitor) { return new ParallelSettings().maxThreadNum(maxThreadNum).splitor(splitor); } /** * * * @param maxThreadNum * @param executor * @return */ public static ParallelSettings create(final int maxThreadNum, final Executor executor) { return new ParallelSettings().maxThreadNum(maxThreadNum).executor(executor); } /** * * * @param splitor * @param executor * @return */ public static ParallelSettings create(final Splitor splitor, final Executor executor) { return new ParallelSettings().splitor(splitor).executor(executor); } /** * * * @param maxThreadNum * @param splitor * @param executor * @return */ public static ParallelSettings create(final int maxThreadNum, final Splitor splitor, final Executor executor) { return new ParallelSettings().maxThreadNum(maxThreadNum).splitor(splitor).executor(executor); } } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy