JB Header
Java 8 Streams API - creating infinite streams with iterate and generate methods
Introduction This tutorial explains how to create infinite streams using the Java 8 Stream API's iterate() and generate() methods with examples to show their usage. This tutorial assumes that you are familiar with basics of Java 8 Streams APIRead Basics of Java 8 Streams API. Infinite Streams Streams are different from collections although they can be created from collections. Unlike collections, a stream can go on generating/producing values forever. Java 8 Streams API provides two static methods in the Stream interface for creating infinite streams. These are Stream.iterate() and Stream.generate().

Since infinite streams need to be limited to a finite number, based on specific requirement, hence it is a common practice to limit the number of elements produced by a stream using the Stream.limit() method.

Let us now take a look at how Stream.iterate() and Stream.generate() methods can be used to produce infinite streams. Creating infinite Streams using the Stream.iterate() method Let us start by looking at the signature of Stream.iterate() method -
static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
Where,
     - first input parameter is a seed value or initial value of type T
     - second input parameter is a UnaryOperator function of type T
     - output is a Stream of type T
Stream.iterate() method works just like a function-of algebraic operation which is commonly written as ƒ(x). The method first returns the seed-value itself. For the 2nd element in the Stream it finds ƒ(seed-value) and from then on iteratively keeps applying function-of to the returned values.
So,
The 1st value in the infinite Stream<T> will be the seed-value
The 2nd value will be ƒ(seed-value).
The 3rd value will be ƒ(ƒ(seed-value))
The 4th value will be ƒ(ƒ(ƒ(seed-value))) and so on...

Let us take an example to understand how Stream.iterate() method works -
Suppose the UnaryOperator<T> function fsqr() is a square function defined using the lambda expression - (Integer n) -> n*n and the seed is 2.
So,
The 1st value returned in the infinite stream will be 2
The 2nd value returned in the stream will be fsqr(2) OR 2*2=4.
The 3rd value will be fsqr(fsqr(2)) i.e. fsqr(4) OR 4*4=16
The 4th value will be fsqr(fsqr(fsqr(2))) i.e. fsqr(16) OR 16*16=256 and so on...
The infinite stream will then have values - [2,4,16,256,... and so on...]

The Java code for using Stream.iterate() method to produce a Stream of iteratively squared values will be as below -
Java 8 code to produce an infinite Stream using Stream.iterate()
package com.javabrahman.java8.streams;
import java.util.stream.Stream;
public class InfiniteStreams {
  public static void main(String args[]){
    Stream.iterate(2, (Integer n) -> n*n)
          .limit(5)
          .forEach(System.out::println);
  }
}
 OUTPUT of the above code
2
4
16
256
65536
Explanation of the code
  • Seed passed as input to the Stream.iterate() method is 2.
  • UnaryOperator function instance is passed using the lambda expression- (Integer n) -> n*n.
  • The output stream is limited to 5 elements using Stream.limit() method.
  • Output Stream is as expected with values - 2,4,16,256,65536.
Creating infinite Streams using the Stream.generate() method Stream.generate() method generates an infinite stream of elements by repeatedly invoking a Supplier Functional InterfaceRead tutorial on Supplier Functional Interface instance passed to it as an input parameter. Stream.generate() method's signature looks like this -
static<T> Stream<T> generate(Supplier<T> s)
Where,
     - Only input is an instance of a Supplier Functional Interface of Type T
     - Output is a Stream of type T

Let us now look at how to write the code to create an infinite stream containing random values using Stream.generate() and Math.random() methods.
Java 8 code to produce an infinite Stream using Stream.generate()
package com.javabrahman.java8.streams;
import java.util.stream.Stream;
public class InfiniteStreams {
  public static void main(String args[]) {
    Stream.generate(Math::random)
        .limit(5)
        .forEach(System.out::println);
  }
}
 OUTPUT of the above code
0.8756068395647292
0.7717064739685572
0.8199061254640724
0.6481411588818413
0.8075238156216996
Explanation of the code
  • Math.random() method generates a random value between 0.0 and 1.0 every time it is called. The function descriptorRead tutorial on Java 8 Function Descriptors of Math.random() method matches that of the Supplier Functional Interface, so Math.random() is passed as an input to Stream.generate() method using its method referenceClick to Read Tutorial on Java 8's Method References - Math::random.
  • Stream.generate() method invokes Math.random() repeatedly to produce an infinite Stream of values between 0.0 and 1.0.
  • The output stream is limited to 5 elements using Stream.limit() method.
  • Output Stream is as expected with 5 random values as shown above..
Summary In this tutorial we looked at what are infinite streams and how they can be generated using the static Stream.iterate() and Stream.generate() methods with Java 8 code examples to understand their usage.