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 extends S> 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 extends S> 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 extends RuntimeException> 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