Analyze Java Stream operations
Debug tool window: View | Tool Windows | Debug or Alt05
Java 8 Streams may sometimes be difficult to debug. This happens because they require you to insert additional breakpoints and thoroughly analyze each transformation inside the stream. IntelliJ IDEA provides a solution to this by letting you visualize what is going on in Java Stream operations.
note
This feature is only available for project files. Java Stream debugger doesn't work with libraries or decompiled code.
Let's take a simple program written in functional style to demonstrate how the feature works.
import java.util.stream.IntStream;
class PrimeFinder {
static int skip = 0;
static int limit = 100;
public static void main(String[] args) {
if (args.length >= 1) skip = Integer.parseInt(args[0]);
if (args.length >= 2) limit = Integer.parseInt(args[1]);
IntStream.iterate(1, n -> n + 1)
.skip(skip)
.limit(limit)
.filter(PrimeTest::isPrime)
.forEach(System.out::println);
}
}
class PrimeTest {
static boolean isPrime(int candidate) {
return candidate == 91 || // a bug here
IntStream.rangeClosed(2, (int) Math.sqrt(candidate))
.noneMatch(n -> (candidate % n == 0));
}
}
As its name suggests, the PrimeFinder
app finds prime numbers. You can specify the starting number and the number of candidates to check using the program arguments. The checking logic is handled by a Java 8 Stream.
Now if we look at the program output, we see extra numbers there.
79
83
89
91 <- extra
97
Concise as the functional style may be, it is not always easy to debug. To understand where these incorrect numbers are coming from, use the stream debugger feature.
Suspend the program at a line where the stream is used. You can use any stream operation for this including terminal ones.
Click the Trace Current Stream Chain button
in the Debug tool window.
Use the Stream Trace dialog to analyze the operations inside the stream. The tabs in the top part let you switch between particular operations and see how the values are transformed with each operation.
If you want to get a bird's eye view of the entire stream, click Flat Mode.
tip
Terminal operations without a return value like
forEach
are not displayed in the Flat Mode.
The examination of the stream gave us a clue about the cause of the problem. We passed a method reference to filter
and it returned an extra value. The search of a bug is now narrowed down to the Predicate
of the filter
operation, that is the PrimeTest.isPrime()
method.
Note that stream trace does not reach beyond the terminal operation of a stream. This means that if there is further chaining, for example with Optional
, it will not be visible from the Stream Trace dialog.
Thanks for your feedback!