package com.annimon.stream;
import com.annimon.stream.function.BinaryOperator;
import com.annimon.stream.function.Consumer;
import com.annimon.stream.function.DoubleBinaryOperator;
import com.annimon.stream.function.Function;
import com.annimon.stream.function.IntBinaryOperator;
import com.annimon.stream.function.LongBinaryOperator;
import com.annimon.stream.iterator.LsaIterator;
import com.annimon.stream.iterator.PrimitiveIterator;
import java.util.ArrayDeque;
import java.util.Iterator;
/**
* Custom operator examples for {@code Stream.custom) method.
*
* @see com.annimon.stream.Stream#custom(com.annimon.stream.function.Function)
*/
public final class CustomOperators {
private CustomOperators() { }
/**
* Example of intermediate operator, that produces reversed stream.
*
* @param <T>
*/
public static class Reverse<T> implements Function<Stream<T>, Stream<T>> {
@Override
public Stream<T> apply(Stream<T> stream) {
final Iterator<? extends T> iterator = stream.iterator();
final ArrayDeque<T> deque = new ArrayDeque<T>();
while (iterator.hasNext()) {
deque.addFirst(iterator.next());
}
return Stream.of(deque.iterator());
}
}
/**
* Example of combining {@code Stream} operators.
*
* @param <T>
*/
public static class SkipAndLimit<T> implements Function<Stream<T>, Stream<T>> {
private final int skip, limit;
public SkipAndLimit(int skip, int limit) {
this.skip = skip;
this.limit = limit;
}
@Override
public Stream<T> apply(Stream<T> stream) {
return stream.skip(skip).limit(limit);
}
}
/**
* Example of terminal operator, that reduces stream to calculate sum on integer elements.
*/
public static class Sum implements Function<Stream<Integer>, Integer> {
@Override
public Integer apply(Stream<Integer> stream) {
return stream.reduce(0, new BinaryOperator<Integer>() {
@Override
public Integer apply(Integer value1, Integer value2) {
return value1 + value2;
}
});
}
}
/**
* Example of terminal forEach operator.
*
* @param <T>
*/
public static class ForEach<T> implements Function<Stream<T>, Void> {
private final Consumer<? super T> action;
public ForEach(Consumer<? super T> action) {
this.action = action;
}
@Override
public Void apply(Stream<T> stream) {
final Iterator<? extends T> iterator = stream.iterator();
while (iterator.hasNext()) {
action.accept(iterator.next());
}
return null;
}
}
/**
* Example of intermediate operator, that casts elements in the stream.
*
* @param <T>
* @param <R>
*/
public static class Cast<T, R> implements Function<Stream<T>, Stream<R>> {
private final Class<R> clazz;
public Cast(Class<R> clazz) {
this.clazz = clazz;
}
@Override
public Stream<R> apply(final Stream<T> stream) {
final Iterator<? extends T> iterator = stream.iterator();
return Stream.of(new LsaIterator<R>() {
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public R nextIteration() {
return clazz.cast(iterator.next());
}
});
}
}
/**
* Example of intermediate flatMap operator.
*
* @param <T>
* @param <R>
*/
public static class FlatMap<T, R> implements Function<Stream<T>, Stream<R>> {
private final Function<? super T, ? extends Stream<R>> mapper;
public FlatMap(Function<? super T, ? extends Stream<R>> mapper) {
this.mapper = mapper;
}
@Override
public Stream<R> apply(final Stream<T> stream) {
final Iterator<? extends T> iterator = stream.iterator();
return Stream.of(new LsaIterator<R>() {
private Iterator<? extends R> inner;
@Override
public boolean hasNext() {
fillInnerIterator();
return inner != null && inner.hasNext();
}
@Override
public R nextIteration() {
fillInnerIterator();
return inner.next();
}
private void fillInnerIterator() {
if ((inner != null) && inner.hasNext()) {
return;
}
while (iterator.hasNext()) {
final T arg = iterator.next();
final Stream<? extends R> result = mapper.apply(arg);
if (result != null) {
inner = result.iterator();
if (inner.hasNext()) {
return;
}
}
}
}
});
}
}
/**
* Example of intermediate zip operator applying on two {@code IntStream}.
*/
public static class Zip implements Function<IntStream, IntStream> {
private final IntStream secondStream;
private final IntBinaryOperator combiner;
public Zip(IntStream secondStream, IntBinaryOperator combiner) {
this.secondStream = secondStream;
this.combiner = combiner;
}
@Override
public IntStream apply(IntStream firstStream) {
final PrimitiveIterator.OfInt it1 = firstStream.iterator();
final PrimitiveIterator.OfInt it2 = secondStream.iterator();
return IntStream.of(new PrimitiveIterator.OfInt() {
@Override
public boolean hasNext() {
return it1.hasNext() && it2.hasNext();
}
@Override
public int nextInt() {
return combiner.applyAsInt(it1.nextInt(), it2.nextInt());
}
});
}
}
/**
* Example of intermediate zip operator applying on two {@code LongStream}.
*/
public static class ZipLong implements Function<LongStream, LongStream> {
private final LongStream secondStream;
private final LongBinaryOperator combiner;
public ZipLong(LongStream secondStream, LongBinaryOperator combiner) {
this.secondStream = secondStream;
this.combiner = combiner;
}
@Override
public LongStream apply(LongStream firstStream) {
final PrimitiveIterator.OfLong it1 = firstStream.iterator();
final PrimitiveIterator.OfLong it2 = secondStream.iterator();
return LongStream.of(new PrimitiveIterator.OfLong() {
@Override
public boolean hasNext() {
return it1.hasNext() && it2.hasNext();
}
@Override
public long nextLong() {
return combiner.applyAsLong(it1.nextLong(), it2.nextLong());
}
});
}
}
/**
* Example of terminal operator that calculates arithmetic mean of values.
*/
public static class Average implements Function<IntStream, Double> {
@Override
public Double apply(IntStream stream) {
long count = 0, sum = 0;
final PrimitiveIterator.OfInt it = stream.iterator();
while (it.hasNext()) {
count++;
sum += it.nextInt();
}
return (count == 0) ? 0 : sum / (double) count;
}
}
/**
* Example of terminal operator that calculates arithmetic mean of values.
*/
public static class AverageLong implements Function<LongStream, Double> {
@Override
public Double apply(LongStream stream) {
long count = 0, sum = 0;
final PrimitiveIterator.OfLong it = stream.iterator();
while (it.hasNext()) {
count++;
sum += it.nextLong();
}
return (count == 0) ? 0 : sum / (double) count;
}
}
/**
* Example of intermediate zip operator applying on {@code DoubleStream} and {@code IntStream}.
*/
public static class ZipWithIntStream implements Function<DoubleStream, DoubleStream> {
private final IntStream secondStream;
private final DoubleBinaryOperator combiner;
public ZipWithIntStream(IntStream secondStream, DoubleBinaryOperator combiner) {
this.secondStream = secondStream;
this.combiner = combiner;
}
@Override
public DoubleStream apply(DoubleStream firstStream) {
final PrimitiveIterator.OfDouble it1 = firstStream.iterator();
final PrimitiveIterator.OfInt it2 = secondStream.iterator();
return DoubleStream.of(new PrimitiveIterator.OfDouble() {
@Override
public boolean hasNext() {
return it1.hasNext() && it2.hasNext();
}
@Override
public double nextDouble() {
return combiner.applyAsDouble(it1.nextDouble(), it2.nextInt());
}
});
}
}
/**
* Example of terminal operator that calculates count, sum, and arithmetic mean of values.
*/
public static class DoubleSummaryStatistics implements Function<DoubleStream, double[]> {
@Override
public double[] apply(DoubleStream stream) {
long count = 0;
double sum = 0;
final PrimitiveIterator.OfDouble it = stream.iterator();
while (it.hasNext()) {
count++;
sum += it.nextDouble();
}
double average = (count == 0) ? 0 : (sum / (double) count);
return new double[] {count, sum, average};
}
}
}