Java 8 has brought a lot of features and Stream API is one of the most popular feature of the Java 8. In this post, we will see as how to create infinite stream with Java 8.
Infinite stream with Java 8
There are mainly two methods defined in the Stream class to create infinite streams and both are static methods
defined in the Stream class.
Stream.iterate()
Stream.generate()
Before we dive into the details of infinite stream with Java 8, let’s start with a few basic concepts of Java Stream API
1. Intermediate and terminal operations
There are many operations that can be used with a stream object. A pipeline is created whenever we create a stream from a source. We can put these operations inside the pipeline to get the desired output. Stream operations are divided into categories: intermediate
and terminal
. Intermediate operations return one stream and terminal operations return non-stream values.
Both of these intermediate
and terminal
operations are combined to create a stream pipeline.We create a stream pipeline from a source like an array
or collection
and it is followed by zero or more intermediate
operations and finally a terminal operation. We can’t use a stream after the terminal operation is completed. The stream is considered as consumed.Following are the intermediate operations we can use with a stream:
filter()
sorted()
limit()
distinct()
skip()
map()
And terminal operations are:
forEach()
collect()
reduce()
min()
max()
count()
allMatch()
anyMatch()
noneMatch()
findAny()
findFirst()
toArray()
forEachOrdered()
We can use more than one intermediate operation, but these operations will be executed only after a terminal operation is called. All intermediate operations are executed immediately once a terminal operation is called.We can also create an infinite stream without using a terminal operation. It will run for an indefinite amount of time, similar to an infinite loop.
2. How to create an infinite stream
Collections are not infinite. We can hold only a finite number of values in a collection. But stream can produce values infinitely.Stream API has two different static methods defined to create an infinite stream
: generate and iterate. The generate method is defined as below:
static <T> Stream<T> generate(Supplier<T> s)
T
is the type of stream elements and s
is the supplier. The supplier is used to generate each value in the stream. It returns an infinite sequential unordered stream.The Iterate method is defined as below:
static <T> Stream<T> iterate(T seed,UnaryOperator<T> fn)
Similar to generate()
, T
is the type of stream elements. seed is the initial element. This element is used with the function fn
to produce the elements. The function fn
is applied to the previous element to produce the current element.This method returns an infinite sequential ordered stream.The difference between Stream.iterate
and Stream.generate
is that Stream.iterate
returns one infinite sequential ordered stream but Stream.generate
returns one infinite sequential unordered stream. We can use any of these two methods to create an infinite stream.
2.1 Example
Let’s try to understand Stream.iterate
with an example. As we have seen before, the first argument of Stream.iterate
is a seed
or starting value and the second argument is a <em>function</em>/<em>UnaryOperator</em>
that calculates the current value based on the previous value.Let’s take a look at the below example:
import java.util.stream.Stream;
class Example {
public static void main(String[] args) {
Stream < Integer > intStream = Stream.iterate(2, i - > i * 2);
intStream.limit(5).forEach(System.out::println);
}
}
Output:
2
4
8
16
32
Let’s take a look at some important points:
- We are using
Stream.iterate
to produce an infinite stream and that is stored in the variableintStream
. - Intermediate operation
limit
is used to limit the output to5
elements. We can’t use an intermediate operation without aterminal
operation. So,<a aria-label="forEach (opens in a new tab)" href="https://javadevjournal.com/java/java-loops/" target="_blank" rel="noreferrer noopener" class="rank-math-link">forEach</a>
is used, which is a terminal operation, to print the values. - The function multiplies the current value by
2
. The initial value is or seed is2
. So it prints2
at first. Then it prints<em>4</em>,
by multiplying2
by2
, next4* 2
i.e.8
, etc. It is using the previous value to calculate the current value.
2.2. Stream.generate method to create an infinite stream with Java 8
The <em>Stream</em>.<em>generate</em>
method takes only one function and generates the data using that function. Let’s try it with an example program:
import java.util.stream.Stream;
class Example {
private static long getCurrentTime() {
return System.currentTimeMillis();
}
public static void main(String[] args) {
Stream < Long > longStream = Stream.generate(Example::getCurrentTime);
longStream.limit(5).forEach(System.out::println);
}
}
Output:
1619272695864
1619272695865
1619272695865
1619272695865
1619272695865
- The
getCurrentTime
is a method that returns the current time in milliseconds. This function is passed toStream.generate()
. We are using method referenceExample::getCurrentTime
to pass this function. - The
Stream.generate
callsgetCurrentTime
repeatedly to produce an infinite stream oflong
values. - Similar to the above example, we are using intermediate operation limit to set a limit of 5 elements and terminal operation foreach to print the values.
2.3 Create an infinite integer stream
In this example, we will create an infinite integer stream. We can use IntStream.iterate or <em>IntStream.generate</em>
to create an infinite stream. Let’s take a look at the below example:
import java.util.stream.IntStream;
class Example {
public static void main(String[] args) {
IntStream.iterate(0, i - > i + 1).forEach(System.out::println);
}
}
If you run this program, it will keep running indefinitely. We are using iterate with the seed value 0. On each step, it is adding 1 to the previous value. The forEach terminal operator is used to print the values in a new line.Since we are not using any intermediate operator, it will not stop. Either you need to stop it manually or it will run out of memory error.
2.4. Create an infinite random integer stream
The above example uses IntStream.iterate
to create an infinite integer stream. In this example, we will use IntStream.generate
. As explained before, this method takes one function
and generates the values based on this function. Since we need to create an infinite random integer stream, We can pass one random number generator function to IntStream.generate
. Below is the complete program:
import java.util.Random;
import java.util.stream.IntStream;
class Example {
public static void main(String[] args) {
IntStream.generate(() - > new Random().nextInt(1000)).forEach(System.out::println);
}
}
Output:
69
437
932
890
815
156
It might produce different outputs on your machine. Since we are not using any terminal operation here, this program will keep running indefinitely and it will keep printing random numbers until we stop the program.We can use a terminal operation like <em>limit()</em>
to limit the number of execution.
2.5 Create an infinite stream with custom objects
In a real-world application, we have to deal with custom objects rather than predefined data types. It works in a similar manner. Let’s take a look at the below program
import java.io.Serializable;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.Stream;
class Student implements Serializable {
private static final Random random = new Random(1000);
private final long id;
public Student() {
id = random.nextInt(10000);
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
'}';
}
}
class Example {
public static void main(String[] args) {
List < Student > studentList = Stream.generate(Student::new).skip(20).limit(5).collect(Collectors.toList());
System.out.println(studentList);
}
}
- We are creating an
<em>infinite stream</em>
of Student objects. Thegenerate
method creates a new Student object each time. - It is adding one id to the Student object once it is created. The id is created by using the random class. Note that we are using a static variable to create the Random object. This will ensure that it uses the same Random object on each object creation.
- By using
skip
andlimit
intermediate operations, we are skipping the first20
values from the stream and limiting it to 5.Collect
terminal operation collects the data in a list.
If you run this program, it will print something like below
Student{id=3022}, Student{id=871}, Student{id=2589}, Student{id=2}, Student{id=1693}]
Summary
In this article we saw how to create infinite stream with Java 8.We learned how to create an infinite stream using Stream.iterate()
and Stream.generate()
methods with different examples. The source code for this article is available on the GitHub repository.