# Analyze Java Stream operations

> **TL;DR**
> Debug tool window: `View | Tool Windows | Debug` or `Alt+5` (Windows), `⌘ 5` (macOS), `⌘ 5` (IntelliJ IDEA Classic (macOS)), `⌘ 5` (macOS System Shortcuts), `Alt+5` (XWin), `Alt+5` (GNOME), `Alt+5` (KDE), `Alt+5` (Emacs), `Alt+5` (Sublime Text), `⌘ 5` (Sublime Text (macOS)), `Alt+5` (NetBeans), `Alt+5` (Visual Studio), `⌘ 5` (Visual Studio (macOS)), `Alt+5` (Eclipse), `⌘ 5` (Eclipse (macOS))

Procedure: Install the Java Stream Debugger plugin

This functionality relies on the [Java Stream Debugger](https://plugins.jetbrains.com/plugin/9696-java-stream-debugger)  plugin, which   you need to install and enable.

1. Press `Ctrl+Alt+S` (Windows), `⌘ Comma` (macOS), `⌘ Comma` (IntelliJ IDEA Classic (macOS)), `⌘ Comma` (macOS System Shortcuts), `Ctrl+Alt+S` (XWin), `Ctrl+Alt+S` (GNOME), `Ctrl+Alt+S` (KDE), `Ctrl+Alt+S` (Emacs), `Ctrl+Alt+S` (Sublime Text), `⌘ Comma` (Sublime Text (macOS)), `Ctrl+Alt+S` (NetBeans), `Ctrl+Alt+S` (Visual Studio), `⌘ Comma` (Visual Studio (macOS)), `Ctrl+Alt+S` (Eclipse), `⌘ Comma` (Eclipse (macOS)) to open settings and then select `Plugins`.

2. Open the Marketplace tab, find the Java Stream Debugger plugin, and click Install (restart the IDE if prompted).

Java Streams may sometimes be difficult to debug. This happens because they handle the processing logic behind the scenes, and it might complicate tracing how particular values are derived. To help you debug Java Streams, IntelliJ IDEA lets you visualize what is going on in a Java Stream.

> **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.

```JAVA
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 the classes' names suggest, the 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.

```CONSOLE
79
83
89
91 <- extra
97
```

To understand where these incorrect numbers are coming from, let's use the stream debugger feature.

Procedure:

1. Suspend the program at a line where the stream is used. You can use any stream operation for this including terminal ones.

```JAVA
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) // set breakpoint here
        .skip(skip)
        .limit(limit)
        .filter(PrimeTest::isPrime)
        .forEach(System.out::println);
}
```

2. In the Debug tool window's toolbar, click More ![More button](https://resources.jetbrains.com.cn/help/img/idea/2026.2/app-client.expui.general.moreVertical.svg) then select Trace Current Stream Chain ![Trace Current Stream Chain button](https://resources.jetbrains.com.cn/help/img/idea/2026.2/java-debugger-streams.icons.stream_debugger.svg).

3. 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.

![The Stream Trace dialog](https://resources.jetbrains.com.cn/help/img/idea/2026.2/debug_analyze_streams_2.png)

> **Tip:**
> To get a bird's eye view of all transformations at once, click Flat Mode. Terminal operations without a return value like `forEach` are not displayed in the Flat Mode.

The examination of the stream shows that the extra value is coming from the `filter` operation. The search of a bug is now narrowed down to the `Predicate` of `filter`, or more specifically, `PrimeTest.isPrime()` method.

> **Note:**
> 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.

