Infinite sequential ordered stream

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
Notice the presence of the limit() intermediate operation. Its presence is mandatory; otherwise, the code will run indefinitely. We must explicitly discard the stream; in other words, we must explicitly specify how many elements that match our filter should be collected in the final list. Once the limit has been reached, the infinite stream is discarded.

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset