An infinite sequential ordered stream can be obtained via Stream.iterate(T seed, UnaryOperator<T> f). The resulting stream starts from the specified seed and continues by applying the f function to the previous element (for example, the n element is f(n-1)).
For example, a stream of integers of type 1, 2, 3, ..., n can be created as follows:
Stream<Integer> infStream = Stream.iterate(1, i -> i + 1);
Furthermore, we can use this stream for a variety of purposes. For example, let's use it to fetch a list of the first 10 even integers:
List<Integer> result = infStream
.filter(i -> i % 2 == 0)
.limit(10)
.collect(Collectors.toList());
The List content will be as follows (notice that the infinite stream will create the elements 1, 2, 3, ..., 20, but only the following elements are matching our filter until the limit of 10 elements is reached):
2, 4, 6, 8, 10, 12, 14, 16, 18, 20
But let's assume that we don't want the list of the first 10 even integers, and we actually want the list of even integers until 10 (or any other limit). Starting with JDK 9, we can shape this behavior via a new flavor of Stream.iterate(). This flavor allows us to embed a hasNext predicate directly into the stream declaration (iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next)). The stream terminates as soon as the hasNext predicate returns false:
Stream<Integer> infStream = Stream.iterate(
1, i -> i <= 10, i -> i + 1);
This time, we can remove the limit() intermediate operation since our hasNext predicate imposes the limit of 10 elements:
List<Integer> result = infStream
.filter(i -> i % 2 == 0)
.collect(Collectors.toList());
The resulting List is as follows (conforming to our hasNext predicate, the infinite stream creates the elements 1, 2, 3, ..., 10, but only the following five elements match our stream filter):
2, 4, 6, 8, 10
Of course, we can combine this flavor of Stream.iterate() and limit() to shape more complex scenarios. For example, the following stream will create new element until the have next predicate, i -> i <= 10. Since we are using random values, the moment when the hasNext predicate will return false is nondeterministic:
Stream<Integer> infStream = Stream.iterate(
1, i -> i <= 10, i -> i + i % 2 == 0
? new Random().nextInt(20) : -1 * new Random().nextInt(10));
One possible output for this stream is as follows:
1, -5, -4, -7, -4, -2, -8, -8, ..., 3, 0, 4, -7, -6, 10, ...
Now, the following pipeline will collect a maximum of 25 numbers that were created via infStream:
List<Integer> result = infStream
.limit(25)
.collect(Collectors.toList());
Now, the infinite stream can be discarded from two places. If the hasNext predicate returns false until we collect 25 elements, then we remain with the collected elements at that moment (less than 25). If the hasNext predicate doesn't return false until we collect 25 elements, then the limit() operation will discard the rest of the stream.