functionalj.stream.StreamPlus Maven / Gradle / Ivy
Show all versions of functionalj-core Show documentation
// ============================================================================
// Copyright (c) 2017-2021 Nawapunth Manusitthipol (NawaMan - http://nawaman.net).
// ----------------------------------------------------------------------------
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// ============================================================================
package functionalj.stream;
import static functionalj.function.Func.themAll;
import static functionalj.stream.StreamPlusHelper.terminate;
import java.util.Collection;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Optional;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.function.ToDoubleFunction;
import java.util.function.ToIntFunction;
import java.util.function.ToLongFunction;
import java.util.stream.Collector;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import functionalj.function.DoubleDoubleFunction;
import functionalj.function.DoubleObjBiFunction;
import functionalj.function.IntIntBiFunction;
import functionalj.function.IntObjBiFunction;
import functionalj.function.LongLongBiFunction;
import functionalj.function.aggregator.Aggregation;
import functionalj.function.aggregator.AggregationToBoolean;
import functionalj.function.aggregator.AggregationToDouble;
import functionalj.function.aggregator.AggregationToInt;
import functionalj.function.aggregator.AggregationToLong;
import functionalj.list.FuncList;
import functionalj.result.NoMoreResultException;
import functionalj.result.Result;
import functionalj.stream.doublestream.DoubleStreamPlus;
import functionalj.stream.intstream.IntStreamPlus;
import functionalj.stream.longstream.LongStreamPlus;
import functionalj.stream.markers.Eager;
import functionalj.stream.markers.Sequential;
import functionalj.stream.markers.Terminal;
import functionalj.tuple.Tuple2;
import lombok.val;
// TODO - Add intersect
// TODO - Add prepare
/**
* This interface allows extension to Java Stream object.
*
*
* - It ensures stream is called and onClose is called.
* - Add many convenience methods
*
*
* Use this class if the source of data is a one-time non-repeatable data source.
* Otherwise, use {@link FuncList} as some operation may benefit from having repeatable streams.
*
* Unless stated otherwise all methods in this class is:
*
* - Lazy.
* - Works for parallel
* - Run in order - if sequence
* - Terminal method must close the stream
*
*
* If any of the rules are not observed, it is a bug.
* See annotations in {@link functionalj.stream.markers} package for more information.
*
* @param the data type.
*
* @author NawaMan -- [email protected]
*/
@FunctionalInterface
public interface StreamPlus
extends
Stream,
AsStreamPlus,
StreamPlusWithCombine,
StreamPlusWithFillNull,
StreamPlusWithFilter,
StreamPlusWithFlatMap,
StreamPlusWithLimit,
StreamPlusWithMap,
StreamPlusWithMapFirst,
StreamPlusWithMapFlat,
StreamPlusWithMapGroup,
StreamPlusWithMapMulti,
StreamPlusWithMapThen,
StreamPlusWithMapToMap,
StreamPlusWithMapToTuple,
StreamPlusWithMapWithIndex,
StreamPlusWithModify,
StreamPlusWithPeek,
StreamPlusWithPipe,
StreamPlusWithSegment,
StreamPlusWithSort,
StreamPlusWithSplit {
/** Throw a no more element exception. This is used for generator. */
public static TARGET noMoreElement() throws NoMoreResultException {
return SupplierBackedIterator.noMoreElement();
}
//== Constructor ==
/** Returns an empty StreamPlus. */
public static StreamPlus empty() {
return StreamPlus
.from(Stream.empty());
}
/** Returns an empty StreamPlus. */
public static StreamPlus emptyStream() {
return empty();
}
/** Create a StreamPlus from the given data. */
@SafeVarargs
public static StreamPlus of(TARGET ... data) {
return ArrayBackedStreamPlus.from(data);
}
/** Create a StreamPlus from the given data */
@SafeVarargs
public static StreamPlus streamOf(TARGET ... data) {
return StreamPlus.of(data);
}
//-- from other type --
/** Create a StreamPlus from the given data. */
public static StreamPlus from(TARGET[] data, int start, int length) {
return ArrayBackedStreamPlus.from(data, start, length);
}
/** Create a StreamPlus from the given stream. */
@SuppressWarnings({ "unchecked", "rawtypes" })
public static StreamPlus from(Stream stream) {
if (stream == null)
return StreamPlus.empty();
return (stream instanceof StreamPlus)
? (StreamPlus)stream
: (StreamPlus)(()->stream);
}
/** Create a StreamPlus from the given iterator. */
public static StreamPlus from(Iterator iterator) {
return IteratorPlus.from(iterator)
.stream();
}
/** Create a StreamPlus from the given iterator. */
public static StreamPlus from(Iterable iterable) {
if (iterable instanceof FuncList) {
return ((FuncList)iterable).streamPlus();
}
return IteratorPlus.from(iterable.iterator())
.stream();
}
/** Create a StreamPlus from the given enumeration. */
public static StreamPlus from(Enumeration enumeration) {
val iterable = (Iterable)() -> new EnumerationBackedIterator(enumeration);
return StreamPlus.from(StreamSupport.stream(iterable.spliterator(), false));
}
/** @return the streams containing null value. */
public static StreamPlus nulls() {
return generateWith(() -> null);
}
/** @return the streams containing null value. */
public static StreamPlus nulls(Class dataClass) {
return generateWith(() -> null);
}
/** Create a list that is the repeat of the given array of data. */
@SuppressWarnings("unchecked")
public static StreamPlus repeat(TARGET ... data) {
return cycle(data);
}
/** Create a list that is the repeat of the given list of data. */
public static StreamPlus repeat(FuncList data) {
return cycle(data);
}
/** Create a FuncList that is the repeat of the given array of data. */
@SafeVarargs
public static StreamPlus cycle(TARGET ... data) {
val size = data.length;
return IntStreamPlus
.wholeNumbers()
.mapToObj(i -> data[i % size]);
}
/** Create a FuncList that is the repeat of the given list of data. */
public static StreamPlus cycle(Collection collection) {
val list = FuncList.from(collection);
val size = list.size();
return IntStreamPlus
.wholeNumbers()
.mapToObj(i -> list.get(i % size));
}
/** Create a FuncList that for an infinite loop - the value is null */
public static StreamPlus loop() {
return nulls();
}
/** Create a FuncList that for a loop with the number of time given - the value is the index of the loop. */
public static StreamPlus loop(int times) {
return nulls((Class)null).limit(times);
}
/** Create a FuncList that for an infinite loop - the value is the index of the loop. */
public static StreamPlus infiniteInt() {
return IntStreamPlus
.wholeNumbers()
.boxed();
}
/** Concatenate all the given streams. */
@SafeVarargs
public static StreamPlus concat(Stream ... streams) {
return streamOf (streams)
.flatMap(themAll());
}
/** Concatenate all streams supplied by the given supplied. */
@SafeVarargs
public static StreamPlus concat(Supplier> ... streams) {
return streamOf (streams)
.map (Supplier::get)
.flatMap(themAll());
}
/** Concatenate all the given streams. */
@SafeVarargs
public static StreamPlus combine(Stream ... streams) {
return streamOf (streams)
.flatMap(themAll());
}
/** Concatenate all streams supplied by the given supplied. */
@SafeVarargs
public static StreamPlus combine(Supplier> ... streams) {
return streamOf (streams)
.map (Supplier::get)
.flatMap(themAll());
}
/**
* Create a StreamPlus from the supplier.
* The supplier will be repeatedly asked for value until NoMoreResultException is thrown.
**/
public static StreamPlus generate(Supplier supplier) {
return generateWith(supplier);
}
/**
* Create a StreamPlus from the supplier.
* The supplier will be repeatedly asked for value until NoMoreResultException is thrown.
**/
public static StreamPlus generateWith(Supplier supplier) {
val iterable = (Iterable)() -> new SupplierBackedIterator(supplier);
return StreamPlus.from(StreamSupport.stream(iterable.spliterator(), false));
}
//== Iterate + Compound ==
/**
* Create a StreamPlus by apply the compounder to the seed over and over.
*
* For example: let say seed = 1 and f(x) = x*2.
* The result stream will be:
* 1 <- seed,
* 2 <- (1*2),
* 4 <- ((1*2)*2),
* 8 <- (((1*2)*2)*2),
* 16 <- ((((1*2)*2)*2)*2)
* ...
*
* Note: this is an alias of compound()
**/
public static StreamPlus iterate(
TARGET seed,
Function compounder) {
return StreamPlus.from(Stream.iterate(seed, compounder::apply));
}
public static StreamPlus iterate(
TARGET seed,
Aggregation aggregation) {
val compounder = aggregation.newAggregator();
return StreamPlus.from(Stream.iterate(seed, compounder::apply));
}
/**
* Create a StreamPlus by apply the compounder to the seed over and over.
*
* For example: let say seed = 1 and f(x) = x*2.
* The result stream will be:
* 1 <- seed,
* 2 <- (1*2),
* 4 <- ((1*2)*2),
* 8 <- (((1*2)*2)*2),
* 16 <- ((((1*2)*2)*2)*2)
* ...
*
* Note: this is an alias of iterate()
**/
public static StreamPlus compound(
TARGET seed,
Function compounder) {
return iterate(seed, compounder);
}
public static StreamPlus compound(
TARGET seed,
Aggregation aggregation) {
return iterate(seed, aggregation);
}
/**
* Create a StreamPlus by apply the compounder to the seeds over and over.
*
* For example: let say seed1 = 1, seed2 = 1 and f(a,b) = a+b.
* The result stream will be:
* 1 <- seed1,
* 1 <- seed2,
* 2 <- (1+1),
* 3 <- (1+2),
* 5 <- (2+3),
* 8 <- (5+8)
* ...
*
* Note: this is an alias of compound()
**/
@Sequential
public static StreamPlus iterate(
TARGET seed1,
TARGET seed2,
BiFunction compounder) {
return StreamPlus.from(StreamSupport.stream(new Spliterators.AbstractSpliterator(Long.MAX_VALUE, 0) {
private final AtomicReference first = new AtomicReference<>(seed1);
private final AtomicReference second = new AtomicReference<>(seed2);
private volatile AtomicBoolean isInOrder = null;
@Override
public boolean tryAdvance(Consumer super TARGET> action) {
if (isInOrder == null) {
action.accept(seed1);
action.accept(seed2);
isInOrder = new AtomicBoolean(true);
}
boolean inOrder = isInOrder.get();
if (inOrder) {
TARGET next = compounder.apply(first.get(), second.get());
action.accept(next);
first.set(next);
} else {
TARGET next = compounder.apply(second.get(), first.get());
action.accept(next);
second.set(next);
}
isInOrder.set(!inOrder);
return true;
}
}, false));
}
/**
* Create a StreamPlus by apply the compounder to the seeds over and over.
*
* For example: let say seed1 = 1, seed2 = 1 and f(a,b) = a+b.
* The result stream will be:
* 1 <- seed1,
* 1 <- seed2,
* 2 <- (1+1),
* 3 <- (1+2),
* 5 <- (2+3),
* 8 <- (5+8)
* ...
*
* Note: this is an alias of iterate()
**/
public static StreamPlus compound(
TARGET seed1,
TARGET seed2,
BiFunction compounder) {
return iterate(seed1, seed2, compounder);
}
//== ZipOf ==
/**
* Create a StreamPlus by combining elements together into a StreamPlus of tuples.
* Only elements with pair will be combined. If this is not desirable, use stream1.zip(stream2).
*
* For example:
* stream1 = [A, B, C, D, E]
* stream2 = [1, 2, 3, 4]
*
* The result stream = [(A,1), (B,2), (C,3), (D,4)].
**/
public static StreamPlus> zipOf(
Stream stream1,
Stream stream2) {
return StreamPlus.from(stream1)
.zipWith(StreamPlus.from(stream2), ZipWithOption.RequireBoth);
}
/**
* Create a StreamPlus by combining elements together using the merger function and collected into the result stream.
* Only elements with pair will be combined. If this is not desirable, use stream1.zip(stream2).
*
* For example:
* stream1 = [A, B, C, D, E]
* stream2 = [1, 2, 3, 4]
* merger = a + "+" + b
*
* The result stream = ["A+1", "B+2", "C+3", "D+4"].
**/
public static StreamPlus zipOf(
Stream stream1,
Stream stream2,
BiFunction merger) {
return StreamPlus.from(stream1)
.zipWith(StreamPlus.from(stream2), ZipWithOption.RequireBoth, merger);
}
/**
* Zip integers from two IntStreams and combine it into another object.
* The result stream has the size of the shortest stream.
*/
public static StreamPlus zipOf(
IntStream stream1,
IntStream stream2,
IntIntBiFunction merger) {
return IntStreamPlus.from(stream1)
.zipToObjWith(stream2, merger);
}
/**
* Zip integers from an int stream and another object stream and combine it into another object.
* The result stream has the size of the shortest stream.
*/
public static StreamPlus zipOf(
IntStream stream1,
Stream stream2,
IntObjBiFunction merger) {
return IntStreamPlus.from(stream1)
.zipWith(stream2, merger);
}
/**
* Zip integers from two IntStreams and combine it into another object.
* The result stream has the size of the shortest stream.
*/
public static StreamPlus zipOf(
LongStream stream1,
LongStream stream2,
LongLongBiFunction merger) {
return LongStreamPlus.from(stream1)
.zipToObjWith(stream2, merger);
}
/**
* Zip integers from two IntStreams and combine it into another object.
* The result stream has the size of the shortest stream.
*/
public static StreamPlus zipOf(
DoubleStream stream1,
DoubleStream stream2,
DoubleDoubleFunction merger) {
return DoubleStreamPlus.from(stream1)
.zipToObjWith(stream2, merger);
}
/**
* Zip integers from an int stream and another object stream and combine it into another object.
* The result stream has the size of the shortest stream.
*/
public static StreamPlus zipOf(
DoubleStream stream1,
Stream stream2,
DoubleObjBiFunction merger) {
return DoubleStreamPlus.from(stream1)
.zipWith(stream2, merger);
}
//== Core ==
/** Return the stream of data behind this StreamPlus. */
public Stream stream();
/** Return this StreamPlus. */
public default StreamPlus streamPlus() {
return this;
}
//-- Derive --
public default StreamPlus derive(
Function, Stream> action) {
return StreamPlus
.from(action.apply(this));
}
public default IntStreamPlus deriveToInt(
Function, IntStream> action) {
return IntStreamPlus
.from(action.apply(this));
}
public default DoubleStreamPlus deriveToDouble(
Function, DoubleStream> action) {
return DoubleStreamPlus
.from(action.apply(this));
}
public default StreamPlus deriveToObj(
Function, Stream> action) {
return StreamPlus
.from(action.apply(this));
}
//-- Characteristics --
/**
* Returns an equivalent stream that is sequential. May return
* itself, either because the stream was already sequential, or because
* the underlying stream state was modified to be sequential.
*
* This is an intermediate
* operation.
*
* @return a sequential stream
*/
@Override
public default StreamPlus sequential() {
return StreamPlus
.from(stream().sequential());
}
/**
* Returns an equivalent stream that is parallel. May return
* itself, either because the stream was already parallel, or because
* the underlying stream state was modified to be parallel.
*
* This is an intermediate
* operation.
*
* @return a parallel stream
*/
@Override
public default StreamPlus parallel() {
return StreamPlus
.from(stream().parallel());
}
/**
* Returns an equivalent stream that is
* unordered. May return
* itself, either because the stream was already unordered, or because
* the underlying stream state was modified to be unordered.
*
* This is an intermediate
* operation.
*
* @return an unordered stream
*/
@Override
public default StreamPlus unordered() {
return StreamPlus
.from(stream().unordered());
}
/**
* Returns whether this stream, if a terminal operation were to be executed,
* would execute in parallel. Calling this method after invoking an
* terminal stream operation method may yield unpredictable results.
*
* @return {@code true} if this stream would execute in parallel if executed
*/
@Override
public default boolean isParallel() {
return stream()
.isParallel();
}
//-- Close --
@Terminal
@Override
public default void close() {
stream()
.close();
}
@Override
public default StreamPlus onClose(Runnable closeHandler) {
return StreamPlus.from(stream().onClose(closeHandler));
}
//-- Iterator --
/** @return a iterator of this FuncList. */
@Override
public default IteratorPlus iterator() {
return IteratorPlus.from(stream().iterator());
}
/** @return a spliterator of this FuncList. */
@Override
public default Spliterator spliterator() {
val iterator = iterator();
return Spliterators.spliteratorUnknownSize(iterator, 0);
}
//== Functionalities ==
//-- Map --
@Override
public default StreamPlus map(Function super DATA, ? extends T> mapper) {
return StreamPlus.from(stream().map(mapper));
}
@Override
public default IntStreamPlus mapToInt(ToIntFunction super DATA> mapper) {
return IntStreamPlus.from(stream().mapToInt(mapper));
}
@Override
public default LongStreamPlus mapToLong(ToLongFunction super DATA> mapper) {
return LongStreamPlus.from(stream().mapToLong(mapper));
}
@Override
public default DoubleStreamPlus mapToDouble(ToDoubleFunction super DATA> mapper) {
return DoubleStreamPlus.from(stream().mapToDouble(mapper));
}
@Override
public default StreamPlus mapToObj(Function super DATA, ? extends T> mapper) {
return StreamPlus.from(stream().map(mapper));
}
public default StreamPlus map(Aggregation super DATA, ? extends T> aggregation) {
val mapper = aggregation.newAggregator();
return StreamPlus.from(stream().map(mapper));
}
public default IntStreamPlus mapToInt(AggregationToInt super DATA> aggregation) {
val mapper = aggregation.newAggregator();
return IntStreamPlus.from(stream().mapToInt(mapper));
}
public default LongStreamPlus mapToLong(AggregationToLong super DATA> aggregation) {
val mapper = aggregation.newAggregator();
return LongStreamPlus.from(stream().mapToLong(mapper));
}
public default DoubleStreamPlus mapToDouble(AggregationToDouble super DATA> aggregation) {
val mapper = aggregation.newAggregator();
return DoubleStreamPlus.from(stream().mapToDouble(mapper));
}
public default StreamPlus mapToObj(Aggregation super DATA, ? extends T> aggregation) {
val mapper = aggregation.newAggregator();
return StreamPlus.from(stream().map(mapper));
}
//-- FlatMap --
@Override
public default StreamPlus flatMap(Function super DATA, ? extends Stream extends T>> mapper) {
return StreamPlus.from(stream().flatMap(mapper));
}
@Override
public default IntStreamPlus flatMapToInt(Function super DATA, ? extends IntStream> mapper) {
return IntStreamPlus.from(stream().flatMapToInt(mapper));
}
@Override
public default LongStreamPlus flatMapToLong(Function super DATA, ? extends LongStream> mapper) {
return LongStreamPlus.from(stream().flatMapToLong(mapper));
}
@Override
public default DoubleStreamPlus flatMapToDouble(Function super DATA, ? extends DoubleStream> mapper) {
return DoubleStreamPlus.from(stream().flatMapToDouble(mapper));
}
public default StreamPlus flatMapToObj(Function super DATA, ? extends Stream extends T>> mapper) {
return StreamPlus.from(stream().flatMap(mapper));
}
public default StreamPlus flatMap(Aggregation super DATA, ? extends Stream extends T>> aggregation) {
val mapper = aggregation.newAggregator();
return StreamPlus.from(stream().flatMap(mapper));
}
public default IntStreamPlus flatMapToInt(Aggregation super DATA, ? extends IntStream> aggregation) {
val mapper = aggregation.newAggregator();
return IntStreamPlus.from(stream().flatMapToInt(mapper));
}
public default LongStreamPlus flatMapToLong(Aggregation super DATA, ? extends LongStream> aggregation) {
val mapper = aggregation.newAggregator();
return LongStreamPlus.from(stream().flatMapToLong(mapper));
}
public default DoubleStreamPlus flatMapToDouble(Aggregation super DATA, ? extends DoubleStream> aggregation) {
val mapper = aggregation.newAggregator();
return DoubleStreamPlus.from(stream().flatMapToDouble(mapper));
}
public default StreamPlus flatMapToObj(Aggregation super DATA, ? extends Stream extends T>> aggregation) {
val mapper = aggregation.newAggregator();
return StreamPlus.from(stream().flatMap(mapper));
}
//-- Filter --
@Override
public default StreamPlus filter(Predicate super DATA> predicate) {
return StreamPlus.from(stream().filter(predicate));
}
public default StreamPlus filter(AggregationToBoolean super DATA> aggregation) {
val predicate = aggregation.newAggregator();
return StreamPlus
.from(stream()
.filter(each -> predicate.test(each)));
}
//-- Peek --
@Override
public default StreamPlus peek(Consumer super DATA> action) {
return StreamPlus.from(stream().peek(action));
}
//-- Limit/Skip --
@Override
public default StreamPlus limit(long maxSize) {
return StreamPlus.from(stream().limit(maxSize));
}
@Override
public default StreamPlus skip(long offset) {
return StreamPlus.from(stream().skip(offset));
}
//-- Distinct --
@Override
public default StreamPlus distinct() {
return StreamPlus.from(stream().distinct());
}
//-- Sorted --
@Eager
@Override
public default StreamPlus sorted() {
return StreamPlus.from(stream().sorted());
}
@Eager
@Override
public default StreamPlus sorted(Comparator super DATA> comparator) {
return StreamPlus.from(stream().sorted(comparator));
}
//-- Terminate --
@Eager
@Terminal
@Override
public default void forEach(Consumer super DATA> action) {
terminate(this, stream -> {
stream
.forEach(action);
});
}
@Eager
@Terminal
@Sequential
@Override
public default void forEachOrdered(Consumer super DATA> action) {
terminate(this, stream -> {
stream
.sequential ()
.forEachOrdered(action);
});
}
@Eager
@Terminal
@Override
public default DATA reduce(DATA identity, BinaryOperator reducer) {
return terminate(this, stream -> {
return stream
.reduce(identity, reducer);
});
}
@Eager
@Terminal
@Override
public default Optional reduce(BinaryOperator reducer) {
return terminate(this, stream -> {
return stream
.reduce(reducer);
});
}
@Eager
@Terminal
@Override
public default U reduce(
U identity,
BiFunction accumulator,
BinaryOperator combiner) {
return terminate(this, stream -> {
return stream
.reduce(identity, accumulator, combiner);
});
}
@Eager
@Terminal
@Override
public default R collect(
Supplier supplier,
BiConsumer accumulator,
BiConsumer combiner) {
return terminate(this, stream -> {
return stream
.collect(supplier, accumulator, combiner);
});
}
@Eager
@Terminal
@Override
public default R collect(Collector super DATA, A, R> collector) {
return terminate(this, stream -> {
return stream
.collect(collector);
});
}
@Eager
@Terminal
public default R collect(Aggregation super DATA, R> aggregation) {
val collector = aggregation.collectorPlus();
return terminate(this, stream -> {
return stream
.collect(collector);
});
}
//-- statistics --
@Eager
@Terminal
@Override
public default Optional min(Comparator super DATA> comparator) {
return terminate(this, stream -> {
return stream.min(comparator);
});
}
@Eager
@Terminal
@Override
public default Optional max(Comparator super DATA> comparator) {
return terminate(this, stream -> {
return stream.max(comparator);
});
}
@Eager
@Terminal
@Override
public default long count() {
return terminate(this, stream -> {
return stream
.count();
});
}
//-- Match --
@Terminal
@Override
public default boolean anyMatch(Predicate super DATA> predicate) {
return terminate(this, stream -> {
return stream
.anyMatch(predicate);
});
}
@Eager
@Terminal
@Override
public default boolean allMatch(Predicate super DATA> predicate) {
return terminate(this, stream -> {
return stream
.allMatch(predicate);
});
}
@Eager
@Terminal
@Override
public default boolean noneMatch(Predicate super DATA> predicate) {
return terminate(this, stream -> {
return stream
.noneMatch(predicate);
});
}
@Terminal
public default boolean anyMatch(AggregationToBoolean super DATA> aggregation) {
val aggregator = aggregation.newAggregator();
return terminate(this, stream -> {
return stream
.anyMatch(each -> aggregator.test(each));
});
}
@Eager
@Terminal
public default boolean allMatch(AggregationToBoolean super DATA> aggregation) {
val aggregator = aggregation.newAggregator();
return terminate(this, stream -> {
return stream
.allMatch(each -> aggregator.test(each));
});
}
@Eager
@Terminal
public default boolean noneMatch(AggregationToBoolean super DATA> aggregation) {
val aggregator = aggregation.newAggregator();
return terminate(this, stream -> {
return stream
.noneMatch(each -> aggregator.test(each));
});
}
@Terminal
@Override
public default Optional findFirst() {
return terminate(this, stream -> {
return stream
.findFirst();
});
}
@Terminal
@Override
public default Optional findAny() {
return terminate(this, stream -> {
return stream
.findAny();
});
}
@SuppressWarnings("unchecked")
@Sequential
@Terminal
public default Optional findLast() {
return terminate(this, stream -> {
Object dummy = new Object();
AtomicReference