Week 3 - Data Structures & Testing 

Collections

Generics

Enums

Stream APIs

Unit Testing with JUnit

Debugging in Java

Practice

Assignment

Back end Track

Introduction

In Debugging chapter of the Core program, you learned to debug JavaScript programs in VS Code by setting breakpoints, stepping through code, and inspecting variables. Those concepts transfer directly to Java. The main difference is the environment: instead of VS Code and Node.js, you will use IntelliJ and the JVM.

Debugging in IntelliJ follows the same structure you already know. You pause the program, inspect its state, move through the code one step at a time, and compare what the program is doing with what you expected it to do.

We will not go deep into remote debugging, profilers, or Java Flight Recorder here. Those are useful tools, but you do not need them yet. If you learn the core debugging workflow well, you will be able to pick up more advanced tools later when a project needs them.

Debugging with IntelliJ

IntelliJ's debugger lets you inspect a running Java program in detail. You can pause on a specific line, inspect variables, evaluate expressions, add watches, and step through method calls, and so on.

We will use a small buggy program first, then connect the same skills to a failing JUnit test.

The example: buggy code

This program calculates the final price after applying a discount.

double calculateDiscount(double price, double discountRate) {
  return 100 * discountRate;
}

double finalPrice(double price, double discountRate) {
  var discount = calculateDiscount(price, discountRate);
  return price - discount;
}

void main() {
  IO.println(finalPrice(200, 0.2));
}

We expect:

But the program outputs 180.

Let's debug it to find out why.

1️⃣ Adding a Breakpoint

A breakpoint tells IntelliJ IDEA where to pause your program. For this walkthrough, add a breakpoint on the line that calls calculateDiscount() inside finalPrice().

To add one, click in the left margin next to the line number, as shown below.

image.png

When the breakpoint is active:

2️⃣ Running the Debugger

Click the run icon, then choose Debug 'CalculateDiscount' from the dropdown.

image.png

Intellij will run your program and stop at your breakpoint.

3️⃣ Inspecting Variables

The Debug tab opens automatically in the bottom tool window. The Threads & Variables tab is selected by default:

Image showing the IntelliJ’s debug session’s default start screen. Click the image to zoom in if needed.

Image showing the IntelliJ’s debug session’s default start screen. Click the image to zoom in if needed.

In the Threads & Variables tab, you can see the current values:

<aside> 💡

In compact Java source files, finalized with Java 25, Java still creates a class behind the scenes. That is why you may see this in the debugger even though you did not write a class yourself.

</aside>

The input values are correct, so the bug is probably in the calculation.

4️⃣ Step Over

Let’s step over this line by pressing the button or F8:

image.png

Step Over runs the current line without entering any method calls on that line. Press the Step Over button or use F8.

var discount = calculateDiscount(price, discountRate);

The variable discount becomes 20.0. That is incorrect: 20% of 200 should be 40. We now know the problem is likely inside calculateDiscount().

<aside> 💡

In IntelliJ IDEA, you can inspect variables directly on the running line:

image.png

You can even change a variable manually while paused by pressing Set value in the dialog or using F2. Use this carefully: changing values during debugging is useful for experiments, but it also changes the current run.

</aside>

<aside> 💡

While paused, you can also hover over a variable or expression in the editor. IntelliJ IDEA shows a tooltip with the current value. This is useful for a quick check without searching through the Variables panel.

</aside>

5️⃣ Restart and Step Into (↓)

Now press Restart Debug CalculateDiscount or use Shift+F9 to start debugging again.

image.png

When the program pauses on the same line again, click Step Into or use F7.

image.png

IntelliJ enters the function calculateDiscount

6️⃣ Evaluate Expression

The Evaluate Expression tool lets you run an expression while the program is paused. It can use the variables that are currently in scope.

Highlight the expression you want to evaluate, then click Evaluate Expression or press Alt+F8:

image.png

When we evaluate the current expression, the result is 20.0, which confirms the incorrect calculation:

image.png

In this small example, you may notice the bug just by reading the code. That is fine. The goal is to practice the debugger workflow. In real backend code, a value may come from several method calls, objects, or request fields, and Evaluate Expression helps you test your understanding while the program is running.

<aside> 💡

You can also evaluate multiple lines of code in real time. Expand the expression input into block or multi-line mode:

Invoking  to see all three variables in the result

Invoking List.of() to see all three variables in the result

</aside>

Let's test the correct expression by replacing 100 with price in the Evaluate Expression window. IntelliJ IDEA still provides autocomplete there, which makes experiments safer and faster.

image.png

After evaluating again, we get 40.0. Now that we've confirmed our expression works in real time, we can copy and paste it over the faulty one.

After evaluating again, we get 40.0. Now that we've confirmed our expression works in real time, we can adjust the faulty one:

image.png

Now that we have confirmed the correct expression, we can fix the source code:

double calculateDiscount(double price, double discountRate) {
    return price * discountRate;
}

7️⃣ Step Out (↑)

Step Out finishes the current method and returns to the method that called it. In IntelliJ, this is usually Shift+F8.

Use Step Out when you stepped into a method and have seen enough. For example, if you step into a helper method and confirm it behaves correctly, Step Out takes you back to the caller without stepping through the rest of the helper line by line.

8️⃣ Using the Watch Panel

watch is an expression that IntelliJ IDEA keeps evaluating while the program is paused. Watches are useful when you want to track a value that does not appear as a simple local variable.

You can add a watch in the Threads & Variables tab, or right-click an expression or variable and add it from the context menu:

image.png

Here, discountRate and price * discountRate were added as watches:

Both watches are now visible in the Threads & Variables tab with a spy-glasses icon

Both watches are now visible in the Threads & Variables tab with a spy-glasses icon

9️⃣ Checking the Call Stack

The call stack shows how your program reached the current line. In IntelliJ IDEA, this appears in the Frames view on the left side of the Debug tool window: