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 */ public static class Reverse implements Function, Stream> { @Override public Stream apply(Stream stream) { final Iterator iterator = stream.iterator(); final ArrayDeque deque = new ArrayDeque(); while (iterator.hasNext()) { deque.addFirst(iterator.next()); } return Stream.of(deque.iterator()); } } /** * Example of combining {@code Stream} operators. * * @param */ public static class SkipAndLimit implements Function, Stream> { private final int skip, limit; public SkipAndLimit(int skip, int limit) { this.skip = skip; this.limit = limit; } @Override public Stream apply(Stream 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, Integer> { @Override public Integer apply(Stream stream) { return stream.reduce(0, new BinaryOperator() { @Override public Integer apply(Integer value1, Integer value2) { return value1 + value2; } }); } } /** * Example of terminal forEach operator. * * @param */ public static class ForEach implements Function, Void> { private final Consumer action; public ForEach(Consumer action) { this.action = action; } @Override public Void apply(Stream stream) { final Iterator iterator = stream.iterator(); while (iterator.hasNext()) { action.accept(iterator.next()); } return null; } } /** * Example of intermediate operator, that casts elements in the stream. * * @param * @param */ public static class Cast implements Function, Stream> { private final Class clazz; public Cast(Class clazz) { this.clazz = clazz; } @Override public Stream apply(final Stream stream) { final Iterator iterator = stream.iterator(); return Stream.of(new LsaIterator() { @Override public boolean hasNext() { return iterator.hasNext(); } @Override public R nextIteration() { return clazz.cast(iterator.next()); } }); } } /** * Example of intermediate flatMap operator. * * @param * @param */ public static class FlatMap implements Function, Stream> { private final Function> mapper; public FlatMap(Function> mapper) { this.mapper = mapper; } @Override public Stream apply(final Stream stream) { final Iterator iterator = stream.iterator(); return Stream.of(new LsaIterator() { private Iterator 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 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 { 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 { 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 { @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 { @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 { 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 { @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}; } } }