![JAR search and dependency download from the Maven repository](/logo.png)
javaslang.collection.Stream Maven / Gradle / Ivy
Show all versions of javaslang Show documentation
/* / \____ _ _ ____ ______ / \ ____ __ _______
* / / \/ \ / \/ \ / /\__\/ // \/ \ // /\__\ JΛVΛSLΛNG
* _/ / /\ \ \/ / /\ \\__\\ \ // /\ \ /\\/ \ /__\ \ Copyright 2014-2016 Javaslang, http://javaslang.io
* /___/\_/ \_/\____/\_/ \_/\__\/__/\__\_/ \_// \__/\_____/ Licensed under the Apache License, Version 2.0
*/
package javaslang.collection;
import javaslang.*;
import javaslang.collection.Stream.Cons;
import javaslang.collection.Stream.Empty;
import javaslang.collection.StreamModule.*;
import javaslang.control.Option;
import java.io.*;
import java.util.*;
import java.util.function.*;
import java.util.stream.Collector;
/**
* An immutable {@code Stream} is lazy sequence of elements which may be infinitely long.
* Its immutability makes it suitable for concurrent programming.
*
* A {@code Stream} is composed of a {@code head} element and a lazy evaluated {@code tail} {@code Stream}.
*
* There are two implementations of the {@code Stream} interface:
*
* - {@link Empty}, which represents the empty {@code Stream}.
* - {@link Cons}, which represents a {@code Stream} containing one or more elements.
*
* Methods to obtain a {@code Stream}:
*
*
* // factory methods
* Stream.empty() // = Stream.of() = Nil.instance()
* Stream.of(x) // = new Cons<>(x, Nil.instance())
* Stream.of(Object...) // e.g. Stream.of(1, 2, 3)
* Stream.ofAll(Iterable) // e.g. Stream.ofAll(List.of(1, 2, 3)) = 1, 2, 3
* Stream.ofAll(<primitive array>) // e.g. List.ofAll(new int[] {1, 2, 3}) = 1, 2, 3
*
* // int sequences
* Stream.from(0) // = 0, 1, 2, 3, ...
* Stream.range(0, 3) // = 0, 1, 2
* Stream.rangeClosed(0, 3) // = 0, 1, 2, 3
*
* // generators
* Stream.cons(Object, Supplier) // e.g. Stream.cons(current, () -> next(current));
* Stream.continually(Supplier) // e.g. Stream.continually(Math::random);
* Stream.iterate(Object, Function)// e.g. Stream.iterate(1, i -> i * 2);
*
*
*
* Factory method applications:
*
*
*
* Stream<Integer> s1 = Stream.of(1);
* Stream<Integer> s2 = Stream.of(1, 2, 3);
* // = Stream.of(new Integer[] {1, 2, 3});
*
* Stream<int[]> s3 = Stream.ofAll(new int[] {1, 2, 3});
* Stream<List<Integer>> s4 = Stream.ofAll(List.of(1, 2, 3));
*
* Stream<Integer> s5 = Stream.ofAll(new int[] {1, 2, 3});
* Stream<Integer> s6 = Stream.ofAll(List.of(1, 2, 3));
*
* // cuckoo's egg
* Stream<Integer[]> s7 = Stream.<Integer[]> of(new Integer[] {1, 2, 3});
*
*
*
* Example: Generating prime numbers
*
*
*
* // = Stream(2L, 3L, 5L, 7L, ...)
* Stream.iterate(2L, PrimeNumbers::nextPrimeFrom)
*
* // helpers
*
* static long nextPrimeFrom(long num) {
* return Stream.from(num + 1).find(PrimeNumbers::isPrime).get();
* }
*
* static boolean isPrime(long num) {
* return !Stream.rangeClosed(2L, (long) Math.sqrt(num)).exists(d -> num % d == 0);
* }
*
*
*
* See Okasaki, Chris: Purely Functional Data Structures (p. 34 ff.). Cambridge, 2003.
*
* @param component type of this Stream
* @author Daniel Dietrich, Jörgen Andersson, Ruslan Sennov
* @since 1.1.0
*/
public interface Stream extends Kind1, T>, LinearSeq {
long serialVersionUID = 1L;
/**
* Returns a {@link java.util.stream.Collector} which may be used in conjunction with
* {@link java.util.stream.Stream#collect(java.util.stream.Collector)} to obtain a {@link javaslang.collection.Stream}.
*
* @param Component type of the Stream.
* @return A javaslang.collection.Stream Collector.
*/
static Collector, Stream> collector() {
final Supplier> supplier = ArrayList::new;
final BiConsumer, T> accumulator = ArrayList::add;
final BinaryOperator> combiner = (left, right) -> {
left.addAll(right);
return left;
};
final Function, Stream> finisher = Stream::ofAll;
return Collector.of(supplier, accumulator, combiner, finisher);
}
/**
* Returns an infinitely long Stream of {@code int} values starting from {@code from}.
*
* The {@code Stream} extends to {@code Integer.MIN_VALUE} when passing {@code Integer.MAX_VALUE}.
*
* @param value a start int value
* @return a new Stream of int values starting from {@code from}
*/
static Stream from(int value) {
return Stream.ofAll(Iterator.from(value));
}
/**
* Returns an infinite long Stream of {@code int} values starting from {@code value} and spaced by {@code step}.
*
* The {@code Stream} extends to {@code Integer.MIN_VALUE} when passing {@code Integer.MAX_VALUE}.
*
* @param value a start int value
* @param step the step by which to advance on each next value
* @return a new {@code Stream} of int values starting from {@code from}
*/
static Stream from(int value, int step) {
return Stream.ofAll(Iterator.from(value, step));
}
/**
* Returns an infinitely long Stream of {@code long} values starting from {@code from}.
*
* The {@code Stream} extends to {@code Integer.MIN_VALUE} when passing {@code Long.MAX_VALUE}.
*
* @param value a start long value
* @return a new Stream of long values starting from {@code from}
*/
static Stream from(long value) {
return Stream.ofAll(Iterator.from(value));
}
/**
* Returns an infinite long Stream of {@code long} values starting from {@code value} and spaced by {@code step}.
*
* The {@code Stream} extends to {@code Long.MIN_VALUE} when passing {@code Long.MAX_VALUE}.
*
* @param value a start long value
* @param step the step by which to advance on each next value
* @return a new {@code Stream} of long values starting from {@code from}
*/
static Stream from(long value, long step) {
return Stream.ofAll(Iterator.from(value, step));
}
/**
* Generates an (theoretically) infinitely long Stream using a value Supplier.
*
* @param supplier A Supplier of Stream values
* @param value type
* @return A new Stream
*/
static Stream continually(Supplier extends T> supplier) {
Objects.requireNonNull(supplier, "supplier is null");
return Stream.ofAll(Iterator.continually(supplier));
}
/**
* Generates a (theoretically) infinitely long Stream using a function to calculate the next value
* based on the previous.
*
* @param seed The first value in the Stream
* @param f A function to calculate the next value based on the previous
* @param value type
* @return A new Stream
*/
static Stream iterate(T seed, Function super T, ? extends T> f) {
Objects.requireNonNull(f, "f is null");
return Stream.ofAll(Iterator.iterate(seed, f));
}
/**
* Constructs a Stream of a head element and a tail supplier.
*
* @param head The head element of the Stream
* @param tailSupplier A supplier of the tail values. To end the stream, return {@link Stream#empty}.
* @param value type
* @return A new Stream
*/
@SuppressWarnings("unchecked")
static Stream cons(T head, Supplier extends Stream extends T>> tailSupplier) {
Objects.requireNonNull(tailSupplier, "tailSupplier is null");
return new ConsImpl<>(head, (Supplier>) tailSupplier);
}
/**
* Returns the single instance of Nil. Convenience method for {@code Nil.instance()}.
*
* Note: this method intentionally returns type {@code Stream} and not {@code Nil}. This comes handy when folding.
* If you explicitly need type {@code Nil} use {@linkplain Empty#instance()}.
*
* @param Component type of Nil, determined by type inference in the particular context.
* @return The empty list.
*/
static Stream empty() {
return Empty.instance();
}
/**
* Narrows a widened {@code Stream extends T>} to {@code Stream}
* by performing a type safe-cast. This is eligible because immutable/read-only
* collections are covariant.
*
* @param stream A {@code Stream}.
* @param Component type of the {@code Stream}.
* @return the given {@code stream} instance as narrowed type {@code Stream}.
*/
@SuppressWarnings("unchecked")
static Stream narrow(Stream extends T> stream) {
return (Stream) stream;
}
/**
* Returns a singleton {@code Stream}, i.e. a {@code Stream} of one element.
*
* @param element An element.
* @param The component type
* @return A new Stream instance containing the given element
*/
static Stream of(T element) {
return cons(element, Empty::instance);
}
/**
* Creates a Stream of the given elements.
*
* Stream.of(1, 2, 3, 4)
* = Nil.instance().prepend(4).prepend(3).prepend(2).prepend(1)
* = new Cons(1, new Cons(2, new Cons(3, new Cons(4, Nil.instance()))))
*
* @param Component type of the Stream.
* @param elements Zero or more elements.
* @return A list containing the given elements in the same order.
*/
@SafeVarargs
static Stream of(T... elements) {
Objects.requireNonNull(elements, "elements is null");
return Stream.ofAll(new Iterator() {
int i = 0;
@Override
public boolean hasNext() {
return i < elements.length;
}
@Override
public T next() {
return elements[i++];
}
});
}
/**
* Returns a Stream containing {@code n} values of a given Function {@code f}
* over a range of integer values from 0 to {@code n - 1}.
*
* @param Component type of the Stream
* @param n The number of elements in the Stream
* @param f The Function computing element values
* @return A Stream consisting of elements {@code f(0),f(1), ..., f(n - 1)}
* @throws NullPointerException if {@code f} is null
*/
static Stream tabulate(int n, Function super Integer, ? extends T> f) {
Objects.requireNonNull(f, "f is null");
return Stream.ofAll(Collections.tabulate(n, f));
}
/**
* Returns a Stream containing {@code n} values supplied by a given Supplier {@code s}.
*
* @param Component type of the Stream
* @param n The number of elements in the Stream
* @param s The Supplier computing element values
* @return A Stream of size {@code n}, where each element contains the result supplied by {@code s}.
* @throws NullPointerException if {@code s} is null
*/
static Stream fill(int n, Supplier extends T> s) {
Objects.requireNonNull(s, "s is null");
return Stream.ofAll(Collections.fill(n, s));
}
/**
* Creates a Stream of the given elements.
*
* @param Component type of the Stream.
* @param elements An Iterable of elements.
* @return A list containing the given elements in the same order.
*/
@SuppressWarnings("unchecked")
static Stream ofAll(Iterable extends T> elements) {
Objects.requireNonNull(elements, "elements is null");
if (elements instanceof Stream) {
return (Stream) elements;
} else {
return StreamFactory.create(elements.iterator());
}
}
/**
* Creates a Stream based on the elements of a boolean array.
*
* @param array a boolean array
* @return A new Stream of Boolean values
*/
static Stream ofAll(boolean[] array) {
Objects.requireNonNull(array, "array is null");
return Stream.ofAll(Iterator.ofAll(array));
}
/**
* Creates a Stream based on the elements of a byte array.
*
* @param array a byte array
* @return A new Stream of Byte values
*/
static Stream ofAll(byte[] array) {
Objects.requireNonNull(array, "array is null");
return Stream.ofAll(Iterator.ofAll(array));
}
/**
* Creates a Stream based on the elements of a char array.
*
* @param array a char array
* @return A new Stream of Character values
*/
static Stream ofAll(char[] array) {
Objects.requireNonNull(array, "array is null");
return Stream.ofAll(Iterator.ofAll(array));
}
/**
* Creates a Stream based on the elements of a double array.
*
* @param array a double array
* @return A new Stream of Double values
*/
static Stream ofAll(double[] array) {
Objects.requireNonNull(array, "array is null");
return Stream.ofAll(Iterator.ofAll(array));
}
/**
* Creates a Stream based on the elements of a float array.
*
* @param array a float array
* @return A new Stream of Float values
*/
static Stream ofAll(float[] array) {
Objects.requireNonNull(array, "array is null");
return Stream.ofAll(Iterator.ofAll(array));
}
/**
* Creates a Stream based on the elements of an int array.
*
* @param array an int array
* @return A new Stream of Integer values
*/
static Stream ofAll(int[] array) {
Objects.requireNonNull(array, "array is null");
return Stream.ofAll(Iterator.ofAll(array));
}
/**
* Creates a Stream based on the elements of a long array.
*
* @param array a long array
* @return A new Stream of Long values
*/
static Stream ofAll(long[] array) {
Objects.requireNonNull(array, "array is null");
return Stream.ofAll(Iterator.ofAll(array));
}
/**
* Creates a Stream based on the elements of a short array.
*
* @param array a short array
* @return A new Stream of Short values
*/
static Stream ofAll(short[] array) {
Objects.requireNonNull(array, "array is null");
return Stream.ofAll(Iterator.ofAll(array));
}
static Stream range(char from, char toExclusive) {
return Stream.ofAll(Iterator.range(from, toExclusive));
}
static Stream rangeBy(char from, char toExclusive, int step) {
return Stream.ofAll(Iterator.rangeBy(from, toExclusive, step));
}
static Stream rangeBy(double from, double toExclusive, double step) {
return Stream.ofAll(Iterator.rangeBy(from, toExclusive, step));
}
/**
* Creates a Stream of int numbers starting from {@code from}, extending to {@code toExclusive - 1}.
*
* Examples:
*
*
* Stream.range(0, 0) // = Stream()
* Stream.range(2, 0) // = Stream()
* Stream.range(-2, 2) // = Stream(-2, -1, 0, 1)
*
*
*
* @param from the first number
* @param toExclusive the last number + 1
* @return a range of int values as specified or {@code Nil} if {@code from >= toExclusive}
*/
static Stream range(int from, int toExclusive) {
return Stream.ofAll(Iterator.range(from, toExclusive));
}
/**
* Creates a Stream of int numbers starting from {@code from}, extending to {@code toExclusive - 1},
* with {@code step}.
*
* Examples:
*
*
* Stream.rangeBy(1, 3, 1) // = Stream(1, 2)
* Stream.rangeBy(1, 4, 2) // = Stream(1, 3)
* Stream.rangeBy(4, 1, -2) // = Stream(4, 2)
* Stream.rangeBy(4, 1, 2) // = Stream()
*
*
*
* @param from the first number
* @param toExclusive the last number + 1
* @param step the step
* @return a range of long values as specified or {@code Nil} if
* {@code from >= toInclusive} and {@code step > 0} or
* {@code from <= toInclusive} and {@code step < 0}
* @throws IllegalArgumentException if {@code step} is zero
*/
static Stream rangeBy(int from, int toExclusive, int step) {
return Stream.ofAll(Iterator.rangeBy(from, toExclusive, step));
}
/**
* Creates a Stream of long numbers starting from {@code from}, extending to {@code toExclusive - 1}.
*
* Examples:
*
*
* Stream.range(0L, 0L) // = Stream()
* Stream.range(2L, 0L) // = Stream()
* Stream.range(-2L, 2L) // = Stream(-2L, -1L, 0L, 1L)
*
*
*
* @param from the first number
* @param toExclusive the last number + 1
* @return a range of long values as specified or {@code Nil} if {@code from >= toExclusive}
*/
static Stream range(long from, long toExclusive) {
return Stream.ofAll(Iterator.range(from, toExclusive));
}
/**
* Creates a Stream of long numbers starting from {@code from}, extending to {@code toExclusive - 1},
* with {@code step}.
*
* Examples:
*
*
* Stream.rangeBy(1L, 3L, 1L) // = Stream(1L, 2L)
* Stream.rangeBy(1L, 4L, 2L) // = Stream(1L, 3L)
* Stream.rangeBy(4L, 1L, -2L) // = Stream(4L, 2L)
* Stream.rangeBy(4L, 1L, 2L) // = Stream()
*
*
*
* @param from the first number
* @param toExclusive the last number + 1
* @param step the step
* @return a range of long values as specified or {@code Nil} if
* {@code from >= toInclusive} and {@code step > 0} or
* {@code from <= toInclusive} and {@code step < 0}
* @throws IllegalArgumentException if {@code step} is zero
*/
static Stream rangeBy(long from, long toExclusive, long step) {
return Stream.ofAll(Iterator.rangeBy(from, toExclusive, step));
}
static Stream rangeClosed(char from, char toInclusive) {
return Stream.ofAll(Iterator.rangeClosed(from, toInclusive));
}
static Stream rangeClosedBy(char from, char toInclusive, int step) {
return Stream.ofAll(Iterator.rangeClosedBy(from, toInclusive, step));
}
static Stream rangeClosedBy(double from, double toInclusive, double step) {
return Stream.ofAll(Iterator.rangeClosedBy(from, toInclusive, step));
}
/**
* Creates a Stream of int numbers starting from {@code from}, extending to {@code toInclusive}.
*
* Examples:
*
*
* Stream.rangeClosed(0, 0) // = Stream(0)
* Stream.rangeClosed(2, 0) // = Stream()
* Stream.rangeClosed(-2, 2) // = Stream(-2, -1, 0, 1, 2)
*
*
*
* @param from the first number
* @param toInclusive the last number
* @return a range of int values as specified or {@code Nil} if {@code from > toInclusive}
*/
static Stream rangeClosed(int from, int toInclusive) {
return Stream.ofAll(Iterator.rangeClosed(from, toInclusive));
}
/**
* Creates a Stream of int numbers starting from {@code from}, extending to {@code toInclusive},
* with {@code step}.
*
* Examples:
*
*
* Stream.rangeClosedBy(1, 3, 1) // = Stream(1, 2, 3)
* Stream.rangeClosedBy(1, 4, 2) // = Stream(1, 3)
* Stream.rangeClosedBy(4, 1, -2) // = Stream(4, 2)
* Stream.rangeClosedBy(4, 1, 2) // = Stream()
*
*
*
* @param from the first number
* @param toInclusive the last number
* @param step the step
* @return a range of int values as specified or {@code Nil} if
* {@code from > toInclusive} and {@code step > 0} or
* {@code from < toInclusive} and {@code step < 0}
* @throws IllegalArgumentException if {@code step} is zero
*/
static Stream rangeClosedBy(int from, int toInclusive, int step) {
return Stream.ofAll(Iterator.rangeClosedBy(from, toInclusive, step));
}
/**
* Creates a Stream of long numbers starting from {@code from}, extending to {@code toInclusive}.
*
* Examples:
*
*
* Stream.rangeClosed(0L, 0L) // = Stream(0L)
* Stream.rangeClosed(2L, 0L) // = Stream()
* Stream.rangeClosed(-2L, 2L) // = Stream(-2L, -1L, 0L, 1L, 2L)
*
*
*
* @param from the first number
* @param toInclusive the last number
* @return a range of long values as specified or {@code Nil} if {@code from > toInclusive}
*/
static Stream rangeClosed(long from, long toInclusive) {
return Stream.ofAll(Iterator.rangeClosed(from, toInclusive));
}
/**
* Creates a Stream of long numbers starting from {@code from}, extending to {@code toInclusive},
* with {@code step}.
*
* Examples:
*
*
* Stream.rangeClosedBy(1L, 3L, 1L) // = Stream(1L, 2L, 3L)
* Stream.rangeClosedBy(1L, 4L, 2L) // = Stream(1L, 3L)
* Stream.rangeClosedBy(4L, 1L, -2L) // = Stream(4L, 2L)
* Stream.rangeClosedBy(4L, 1L, 2L) // = Stream()
*
*
*
* @param from the first number
* @param toInclusive the last number
* @param step the step
* @return a range of int values as specified or {@code Nil} if
* {@code from > toInclusive} and {@code step > 0} or
* {@code from < toInclusive} and {@code step < 0}
* @throws IllegalArgumentException if {@code step} is zero
*/
static Stream rangeClosedBy(long from, long toInclusive, long step) {
return Stream.ofAll(Iterator.rangeClosedBy(from, toInclusive, step));
}
/**
* Repeats an element infinitely often.
*
* @param t An element
* @param Element type
* @return A new Stream containing infinite {@code t}'s.
*/
static Stream continually(T t) {
return Stream.ofAll(Iterator.continually(t));
}
@Override
default Stream append(T element) {
return isEmpty() ? Stream.of(element) : new AppendElements<>(head(), Queue.of(element), this::tail);
}
@Override
default Stream appendAll(Iterable extends T> elements) {
Objects.requireNonNull(elements, "elements is null");
return Stream.ofAll(isEmpty() ? elements : Iterator.concat(this, elements));
}
/**
* Appends itself to the end of stream with {@code mapper} function.
*
* Example:
*
* Well known Scala code for Fibonacci infinite sequence
*
*
* val fibs:Stream[Int] = 0 #:: 1 #:: (fibs zip fibs.tail).map{ t => t._1 + t._2 }
*
*
* can be transformed to
*
*
* Stream.of(0, 1).appendSelf(self -> self.zip(self.tail()).map(t -> t._1 + t._2));
*
*
*
* @param mapper an mapper
* @return a new Stream
*/
default Stream appendSelf(Function super Stream, ? extends Stream> mapper) {
Objects.requireNonNull(mapper, "mapper is null");
return isEmpty() ? this : new AppendSelf<>((Cons) this, mapper).stream();
}
@Override
default Stream> combinations() {
return Stream.rangeClosed(0, length()).map(this::combinations).flatMap(Function.identity());
}
@Override
default Stream> combinations(int k) {
return Combinations.apply(this, Math.max(k, 0));
}
@Override
default Iterator> crossProduct(int power) {
return Collections.crossProduct(Stream.empty(), this, power);
}
/**
* Repeat the elements of this Stream infinitely.
*
* Example:
*
*
* // = 1, 2, 3, 1, 2, 3, 1, 2, 3, ...
* Stream.of(1, 2, 3).cycle();
*
*
*
* @return A new Stream containing this elements cycled.
*/
default Stream cycle() {
return isEmpty() ? this : appendSelf(Function.identity());
}
/**
* Repeat the elements of this Stream {@code count} times.
*
* Example:
*
*
* // = empty
* Stream.of(1, 2, 3).cycle(0);
*
* // = 1, 2, 3
* Stream.of(1, 2, 3).cycle(1);
*
* // = 1, 2, 3, 1, 2, 3, 1, 2, 3
* Stream.of(1, 2, 3).cycle(3);
*
*
*
* @param count the number of cycles to be performed
* @return A new Stream containing this elements cycled {@code count} times.
*/
default Stream cycle(int count) {
if (count <= 0 || isEmpty()) {
return empty();
} else {
final Stream self = this;
return Stream.ofAll(new Iterator() {
Stream stream = self;
int i = count - 1;
@Override
public boolean hasNext() {
return !stream.isEmpty() || i > 0;
}
@Override
public T next() {
if (stream.isEmpty()) {
i--;
stream = self;
}
final T result = stream.head();
stream = stream.tail();
return result;
}
});
}
}
@Override
default Stream distinct() {
return distinctBy(Function.identity());
}
@Override
default Stream distinctBy(Comparator super T> comparator) {
Objects.requireNonNull(comparator, "comparator is null");
final java.util.Set seen = new java.util.TreeSet<>(comparator);
return filter(seen::add);
}
@Override
default Stream distinctBy(Function super T, ? extends U> keyExtractor) {
final java.util.Set seen = new java.util.HashSet<>();
return filter(t -> seen.add(keyExtractor.apply(t)));
}
@Override
default Stream drop(long n) {
Stream stream = this;
while (n-- > 0 && !stream.isEmpty()) {
stream = stream.tail();
}
return stream;
}
@Override
default Stream dropRight(long n) {
if (n <= 0) {
return this;
} else {
return DropRight.apply(take(n).toList(), List.empty(), drop(n));
}
}
@Override
default Stream dropUntil(Predicate super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
return dropWhile(predicate.negate());
}
@Override
default Stream dropWhile(Predicate super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
Stream stream = this;
while (!stream.isEmpty() && predicate.test(stream.head())) {
stream = stream.tail();
}
return stream;
}
@Override
default Stream filter(Predicate super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
Stream stream = this;
while (!stream.isEmpty() && !predicate.test(stream.head())) {
stream = stream.tail();
}
final Stream finalStream = stream;
return stream.isEmpty() ? stream : cons(stream.head(), () -> finalStream.tail().filter(predicate));
}
@Override
default Stream flatMap(Function super T, ? extends Iterable extends U>> mapper) {
Objects.requireNonNull(mapper, "mapper is null");
return isEmpty() ? Empty.instance() : Stream.ofAll(new Iterator() {
final Iterator extends T> inputs = Stream.this.iterator();
java.util.Iterator extends U> current = java.util.Collections.emptyIterator();
@Override
public boolean hasNext() {
boolean currentHasNext;
while (!(currentHasNext = current.hasNext()) && inputs.hasNext()) {
current = mapper.apply(inputs.next()).iterator();
}
return currentHasNext;
}
@Override
public U next() {
return current.next();
}
});
}
@Override
default T get(int index) {
if (isEmpty()) {
throw new IndexOutOfBoundsException("get(" + index + ") on Nil");
}
if (index < 0) {
throw new IndexOutOfBoundsException("get(" + index + ")");
}
Stream stream = this;
for (int i = index - 1; i >= 0; i--) {
stream = stream.tail();
if (stream.isEmpty()) {
throw new IndexOutOfBoundsException(String.format("get(%s) on Stream of size %s", index, index - i));
}
}
return stream.head();
}
@Override
default Map> groupBy(Function super T, ? extends C> classifier) {
Objects.requireNonNull(classifier, "classifier is null");
return iterator().groupBy(classifier).map((c, it) -> Tuple.of(c, Stream.ofAll(it)));
}
@Override
default Iterator> grouped(long size) {
return sliding(size, size);
}
@Override
default boolean hasDefiniteSize() {
return false;
}
@Override
default Option headOption() {
return isEmpty() ? Option.none() : Option.some(head());
}
@Override
default int indexOf(T element, int from) {
int index = 0;
for (Stream stream = this; !stream.isEmpty(); stream = stream.tail(), index++) {
if (index >= from && Objects.equals(stream.head(), element)) {
return index;
}
}
return -1;
}
@Override
default Stream init() {
if (isEmpty()) {
throw new UnsupportedOperationException("init of empty stream");
} else {
final Stream tail = tail();
if (tail.isEmpty()) {
return Empty.instance();
} else {
return cons(head(), tail::init);
}
}
}
@Override
default Option> initOption() {
return isEmpty() ? Option.none() : Option.some(init());
}
@Override
default Stream insert(int index, T element) {
if (index < 0) {
throw new IndexOutOfBoundsException("insert(" + index + ", e)");
} else if (index == 0) {
return cons(element, () -> this);
} else if (isEmpty()) {
throw new IndexOutOfBoundsException("insert(" + index + ", e) on Nil");
} else {
return cons(head(), () -> tail().insert(index - 1, element));
}
}
@SuppressWarnings("unchecked")
@Override
default Stream insertAll(int index, Iterable extends T> elements) {
Objects.requireNonNull(elements, "elements is null");
if (index < 0) {
throw new IndexOutOfBoundsException("insertAll(" + index + ", elements)");
} else if (index == 0) {
return isEmpty() ? Stream.ofAll(elements) : Stream.ofAll((Iterable) elements).appendAll(this);
} else if (isEmpty()) {
throw new IndexOutOfBoundsException("insertAll(" + index + ", elements) on Nil");
} else {
return cons(head(), () -> tail().insertAll(index - 1, elements));
}
}
@Override
default Stream intersperse(T element) {
if (isEmpty()) {
return this;
} else {
return cons(head(), () -> {
final Stream tail = tail();
return tail.isEmpty() ? tail : cons(element, () -> tail.intersperse(element));
});
}
}
@Override
default boolean isTraversableAgain() {
return true;
}
@Override
default int lastIndexOf(T element, int end) {
int result = -1, index = 0;
for (Stream stream = this; index <= end && !stream.isEmpty(); stream = stream.tail(), index++) {
if (Objects.equals(stream.head(), element)) {
result = index;
}
}
return result;
}
@Override
default int length() {
return foldLeft(0, (n, ignored) -> n + 1);
}
@Override
default Stream map(Function super T, ? extends U> mapper) {
Objects.requireNonNull(mapper, "mapper is null");
if (isEmpty()) {
return Empty.instance();
} else {
return cons(mapper.apply(head()), () -> tail().map(mapper));
}
}
@Override
default Stream padTo(int length, T element) {
if (length <= 0) {
return this;
} else if (isEmpty()) {
return Stream.ofAll(Iterator.continually(element).take(length));
} else {
return cons(head(), () -> tail().padTo(length - 1, element));
}
}
@Override
default Stream patch(int from, Iterable extends T> that, int replaced) {
from = from < 0 ? 0 : from;
replaced = replaced < 0 ? 0 : replaced;
Stream result = take(from).appendAll(that);
from += replaced;
result = result.appendAll(drop(from));
return result;
}
@Override
default Tuple2, Stream> partition(Predicate super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
return Tuple.of(filter(predicate), filter(predicate.negate()));
}
@Override
default Stream peek(Consumer super T> action) {
Objects.requireNonNull(action, "action is null");
if (isEmpty()) {
return this;
} else {
final T head = head();
action.accept(head);
return cons(head, () -> tail().peek(action));
}
}
@Override
default Stream> permutations() {
if (isEmpty()) {
return Empty.instance();
} else {
final Stream tail = tail();
if (tail.isEmpty()) {
return Stream.of(this);
} else {
final Stream> zero = Empty.instance();
return distinct().foldLeft(zero, (xs, x) -> {
final Function, Stream> prepend = l -> l.prepend(x);
return xs.appendAll(remove(x).permutations().map(prepend));
});
}
}
}
@Override
default Stream prepend(T element) {
return cons(element, () -> this);
}
@SuppressWarnings("unchecked")
@Override
default Stream prependAll(Iterable extends T> elements) {
Objects.requireNonNull(elements, "elements is null");
return Stream.ofAll((Iterable) elements).appendAll(this);
}
@Override
default Stream remove(T element) {
if (isEmpty()) {
return this;
} else {
final T head = head();
return Objects.equals(head, element) ? tail() : cons(head, () -> tail().remove(element));
}
}
@Override
default Stream removeFirst(Predicate predicate) {
Objects.requireNonNull(predicate, "predicate is null");
if (isEmpty()) {
return this;
} else {
final T head = head();
return predicate.test(head) ? tail() : cons(head, () -> tail().removeFirst(predicate));
}
}
@Override
default Stream removeLast(Predicate predicate) {
return isEmpty() ? this : reverse().removeFirst(predicate).reverse();
}
@Override
default Stream removeAt(int index) {
if (index < 0) {
throw new IndexOutOfBoundsException("removeAt(" + index + ")");
} else if (index == 0) {
return tail();
} else if (isEmpty()) {
throw new IndexOutOfBoundsException("removeAt() on Nil");
} else {
return cons(head(), () -> tail().removeAt(index - 1));
}
}
@Override
default Stream removeAll(T removed) {
return filter(e -> !Objects.equals(e, removed));
}
@SuppressWarnings("unchecked")
@Override
default Stream removeAll(Iterable extends T> elements) {
Objects.requireNonNull(elements, "elements is null");
final Stream distinct = Stream.ofAll((Iterable) elements).distinct();
return filter(e -> !distinct.contains(e));
}
@Override
default Stream replace(T currentElement, T newElement) {
if (isEmpty()) {
return this;
} else {
final T head = head();
if (Objects.equals(head, currentElement)) {
return cons(newElement, this::tail);
} else {
return cons(head, () -> tail().replace(currentElement, newElement));
}
}
}
@Override
default Stream replaceAll(T currentElement, T newElement) {
if (isEmpty()) {
return this;
} else {
final T head = head();
final T newHead = Objects.equals(head, currentElement) ? newElement : head;
return cons(newHead, () -> tail().replaceAll(currentElement, newElement));
}
}
@SuppressWarnings("unchecked")
@Override
default Stream retainAll(Iterable extends T> elements) {
Objects.requireNonNull(elements, "elements is null");
if (isEmpty()) {
return this;
} else {
final Stream retained = Stream.ofAll((Iterable) elements).distinct();
return filter(retained::contains);
}
}
@Override
default Stream reverse() {
return isEmpty() ? this : foldLeft(Stream.empty(), Stream::prepend);
}
@Override
default Stream scan(T zero, BiFunction super T, ? super T, ? extends T> operation) {
return scanLeft(zero, operation);
}
@Override
default Stream scanLeft(U zero, BiFunction super U, ? super T, ? extends U> operation) {
Objects.requireNonNull(operation, "operation is null");
// lazily streams the elements of an iterator
return Stream.ofAll(iterator().scanLeft(zero, operation));
}
// not lazy!
@Override
default Stream scanRight(U zero, BiFunction super T, ? super U, ? extends U> operation) {
Objects.requireNonNull(operation, "operation is null");
return Collections.scanRight(this, zero, operation, Stream.empty(), Stream::prepend, Function.identity());
}
@Override
default Stream slice(long beginIndex, long endIndex) {
if (beginIndex >= endIndex || isEmpty()) {
return empty();
} else {
final long lowerBound = Math.max(beginIndex, 0);
if (lowerBound == 0) {
return cons(head(), () -> tail().slice(0, endIndex - 1));
} else {
return tail().slice(lowerBound - 1, endIndex - 1);
}
}
}
@Override
default Iterator> sliding(long size) {
return sliding(size, 1);
}
@Override
default Iterator> sliding(long size, long step) {
return iterator().sliding(size, step).map(Stream::ofAll);
}
@Override
default Stream sorted() {
return isEmpty() ? this : toJavaStream().sorted().collect(Stream.collector());
}
@Override
default Stream sorted(Comparator super T> comparator) {
Objects.requireNonNull(comparator, "comparator is null");
return isEmpty() ? this : toJavaStream().sorted(comparator).collect(Stream.collector());
}
@Override
default > Stream sortBy(Function super T, ? extends U> mapper) {
return sortBy(U::compareTo, mapper);
}
@Override
default Stream sortBy(Comparator super U> comparator, Function super T, ? extends U> mapper) {
final Function super T, ? extends U> domain = Function1.of(mapper::apply).memoized();
return toJavaStream()
.sorted((e1, e2) -> comparator.compare(domain.apply(e1), domain.apply(e2)))
.collect(collector());
}
@Override
default Tuple2, Stream> span(Predicate super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
return Tuple.of(takeWhile(predicate), dropWhile(predicate));
}
@Override
default Tuple2, Stream> splitAt(long n) {
return Tuple.of(take(n), drop(n));
}
@Override
default Tuple2, Stream> splitAt(Predicate super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
return Tuple.of(takeWhile(predicate.negate()), dropWhile(predicate.negate()));
}
@Override
default Tuple2, Stream> splitAtInclusive(Predicate super T> predicate) {
final Tuple2, Stream> split = splitAt(predicate);
if (split._2.isEmpty()) {
return split;
} else {
return Tuple.of(split._1.append(split._2.head()), split._2.tail());
}
}
@Override
default Spliterator spliterator() {
// the focus of the Stream API is on random-access collections of *known size*
return Spliterators.spliterator(iterator(), length(), Spliterator.ORDERED | Spliterator.IMMUTABLE);
}
@Override
default String stringPrefix() {
return "Stream";
}
@Override
default Stream subSequence(int beginIndex) {
if (beginIndex < 0) {
throw new IndexOutOfBoundsException("subSequence(" + beginIndex + ")");
}
Stream result = this;
for (int i = 0; i < beginIndex; i++, result = result.tail()) {
if (result.isEmpty()) {
throw new IndexOutOfBoundsException(
String.format("subSequence(%s) on Stream of size %s", beginIndex, i));
}
}
return result;
}
@Override
default Stream subSequence(int beginIndex, int endIndex) {
if (beginIndex < 0 || beginIndex > endIndex) {
throw new IndexOutOfBoundsException(String.format("subSequence(%s, %s)", beginIndex, endIndex));
}
if (beginIndex == endIndex) {
return Empty.instance();
} else if (isEmpty()) {
throw new IndexOutOfBoundsException("subSequence of Nil");
} else if (beginIndex == 0) {
return cons(head(), () -> tail().subSequence(0, endIndex - 1));
} else {
return tail().subSequence(beginIndex - 1, endIndex - 1);
}
}
@Override
Stream tail();
@Override
default Option> tailOption() {
return isEmpty() ? Option.none() : Option.some(tail());
}
@Override
default Stream take(long n) {
if (n < 1 || isEmpty()) {
return Empty.instance();
} else if (n == 1) {
return cons(head(), Stream::empty);
} else {
return cons(head(), () -> tail().take(n - 1));
}
}
@Override
default Stream takeRight(long n) {
Stream right = this;
Stream remaining = drop(n);
while (!remaining.isEmpty()) {
right = right.tail();
remaining = remaining.tail();
}
return right;
}
@Override
default Stream takeUntil(Predicate super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
return takeWhile(predicate.negate());
}
@Override
default Stream takeWhile(Predicate super T> predicate) {
Objects.requireNonNull(predicate, "predicate is null");
if (isEmpty()) {
return Empty.instance();
} else {
final T head = head();
if (predicate.test(head)) {
return cons(head, () -> tail().takeWhile(predicate));
} else {
return Empty.instance();
}
}
}
/**
* Transforms this {@code Stream}.
*
* @param f A transformation
* @param Type of transformation result
* @return An instance of type {@code U}
* @throws NullPointerException if {@code f} is null
*/
default U transform(Function super Stream, ? extends U> f) {
Objects.requireNonNull(f, "f is null");
return f.apply(this);
}
@Override
default Stream unit(Iterable extends U> iterable) {
return Stream.ofAll(iterable);
}
@Override
default Tuple2, Stream> unzip(
Function super T, Tuple2 extends T1, ? extends T2>> unzipper) {
Objects.requireNonNull(unzipper, "unzipper is null");
final Stream> stream = map(unzipper);
final Stream stream1 = stream.map(t -> t._1);
final Stream stream2 = stream.map(t -> t._2);
return Tuple.of(stream1, stream2);
}
@Override
default Tuple3, Stream, Stream> unzip3(
Function super T, Tuple3 extends T1, ? extends T2, ? extends T3>> unzipper) {
Objects.requireNonNull(unzipper, "unzipper is null");
final Stream> stream = map(unzipper);
final Stream stream1 = stream.map(t -> t._1);
final Stream stream2 = stream.map(t -> t._2);
final Stream stream3 = stream.map(t -> t._3);
return Tuple.of(stream1, stream2, stream3);
}
@Override
default Stream update(int index, T element) {
if (isEmpty()) {
throw new IndexOutOfBoundsException("update(" + index + ", e) on Nil");
}
if (index < 0) {
throw new IndexOutOfBoundsException("update(" + index + ", e)");
}
Stream preceding = Empty.instance();
Stream tail = this;
for (int i = index; i > 0; i--, tail = tail.tail()) {
if (tail.isEmpty()) {
throw new IndexOutOfBoundsException("update at " + index);
}
preceding = preceding.prepend(tail.head());
}
if (tail.isEmpty()) {
throw new IndexOutOfBoundsException("update at " + index);
}
// skip the current head element because it is replaced
return preceding.reverse().appendAll(tail.tail().prepend(element));
}
@Override
default Stream> zip(Iterable iterable) {
Objects.requireNonNull(iterable, "iterable is null");
return Stream.ofAll(iterator().zip(iterable));
}
@Override
default Stream> zipAll(Iterable iterable, T thisElem, U thatElem) {
Objects.requireNonNull(iterable, "iterable is null");
return Stream.ofAll(iterator().zipAll(iterable, thisElem, thatElem));
}
@Override
default Stream> zipWithIndex() {
return Stream.ofAll(iterator().zipWithIndex());
}
/**
* Extends (continues) this {@code Stream} with a constantly repeated value.
*
* @param next value with which the stream should be extended
* @return new {@code Stream} composed from this stream extended with a Stream of provided value
*/
default Stream extend(T next) {
return Stream.ofAll(this.appendAll(Stream.continually(next)));
}
/**
* Extends (continues) this {@code Stream} with values provided by a {@code Supplier}
*
* @param nextSupplier a supplier which will provide values for extending a stream
* @return new {@code Stream} composed from this stream extended with values provided by the supplier
*/
default Stream extend(Supplier extends T> nextSupplier) {
Objects.requireNonNull(nextSupplier, "nextSupplier is null");
return Stream.ofAll(appendAll(Stream.continually(nextSupplier)));
}
/**
* Extends (continues) this {@code Stream} with a Stream of values created by applying
* consecutively provided {@code Function} to the last element of the original Stream.
*
* @param nextFunction a function which calculates the next value basing on the previous value
* @return new {@code Stream} composed from this stream extended with values calculated by the provided function
*/
default Stream extend(Function super T, ? extends T> nextFunction) {
Objects.requireNonNull(nextFunction, "nextFunction is null");
if (isEmpty()) {
return this;
} else {
final Stream that = this;
return Stream.ofAll(new AbstractIterator() {
Stream stream = that;
T last = null;
@Override
protected T getNext() {
if (stream.isEmpty()) {
stream = Stream.iterate(nextFunction.apply(last), nextFunction);
}
last = stream.head();
stream = stream.tail();
return last;
}
@Override
public boolean hasNext() {
return true;
}
});
}
}
/**
* The empty Stream.
*
* This is a singleton, i.e. not Cloneable.
*
* @param Component type of the Stream.
* @since 1.1.0
*/
final class Empty implements Stream, Serializable {
private static final long serialVersionUID = 1L;
private static final Empty> INSTANCE = new Empty<>();
// hidden
private Empty() {
}
/**
* Returns the singleton empty Stream instance.
*
* @param Component type of the Stream
* @return The empty Stream
*/
@SuppressWarnings("unchecked")
public static Empty instance() {
return (Empty) INSTANCE;
}
@Override
public T head() {
throw new NoSuchElementException("head of empty stream");
}
@Override
public boolean isEmpty() {
return true;
}
@Override
public Iterator iterator() {
return Iterator.empty();
}
@Override
public Stream tail() {
throw new UnsupportedOperationException("tail of empty stream");
}
@Override
public boolean equals(Object o) {
return o == this;
}
@Override
public int hashCode() {
return Traversable.hash(this);
}
@Override
public String toString() {
return stringPrefix() + "()";
}
/**
* Instance control for object serialization.
*
* @return The singleton instance of Nil.
* @see java.io.Serializable
*/
private Object readResolve() {
return INSTANCE;
}
}
/**
* Non-empty {@code Stream}, consisting of a {@code head}, and {@code tail}.
*
* @param Component type of the Stream.
* @since 1.1.0
*/
abstract class Cons implements Stream {
private static final long serialVersionUID = 1L;
final T head;
final Lazy> tail;
Cons(T head, Supplier> tail) {
Objects.requireNonNull(tail, "tail is null");
this.head = head;
this.tail = Lazy.of(tail);
}
@Override
public T head() {
return head;
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public Iterator iterator() {
return new StreamIterator<>(this);
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (o instanceof Stream) {
Stream> stream1 = this;
Stream> stream2 = (Stream>) o;
while (!stream1.isEmpty() && !stream2.isEmpty()) {
final boolean isEqual = Objects.equals(stream1.head(), stream2.head());
if (!isEqual) {
return false;
}
stream1 = stream1.tail();
stream2 = stream2.tail();
}
return stream1.isEmpty() && stream2.isEmpty();
} else {
return false;
}
}
@Override
public int hashCode() {
return Traversable.hash(this);
}
@Override
public String toString() {
final StringBuilder builder = new StringBuilder(stringPrefix()).append("(");
Stream stream = this;
while (stream != null && !stream.isEmpty()) {
final Cons