Stage 7: Tools and testing, lesson 5 of 7

Debugging and reading stack traces

Beginner3 min readall versions
Explain it forThe essentials plus production detail and pitfalls.

Read a stack trace from the top. The first line names the exception and its message; the lines below show where it happened, most recent call first. Find the first line that points to your code (your package name); that's usually where to look. A Caused by: section shows the original cause, which is often the real problem.

Use the debugger instead of scattering print statements:

  • A breakpoint pauses at a line; click the gutter to add one.
  • Step over (F8 in IntelliJ) runs the line; step into (F7) enters a method; resume (F9) continues.
  • Inspect variables and evaluate expressions (Alt+F8) while paused.
  • A conditional breakpoint pauses only when a condition holds, such as orderId.equals("ORD-99").

A reliable routine: reproduce the bug, shrink the input, form a hypothesis, test it, fix it, then add a test so the bug never comes back.

Example

Plain text
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "coupon" is null
    at com.javaatlas.billing.PriceCalculator.discount(PriceCalculator.java:42)     <- start here
    at com.javaatlas.billing.CheckoutService.total(CheckoutService.java:27)
    at com.javaatlas.billing.CheckoutController.checkout(CheckoutController.java:19)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(...)
The fix at PriceCalculator.java line 42
BigDecimal discount(BigDecimal price, String coupon) {
    if (coupon == null || coupon.isBlank()) {        // handle the missing coupon explicitly
        return BigDecimal.ZERO;
    }
    return coupons.lookup(coupon)
                  .map(c -> c.apply(price))
                  .orElse(BigDecimal.ZERO);
}

Common mistake

Catching an exception and printing only e.getMessage(). The stack trace is lost; log the exception object itself.

Under the hood

For problems you can't reproduce locally, read the logs around the time of the error, take a thread dump (jcmd <pid> Thread.print) for hangs, and a heap dump for memory problems. Remote debugging (-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005) is powerful but belongs only in safe environments. Since Java 14, helpful NullPointerException messages name the exact null expression, as in the example.

Check yourself

In a stack trace, which frame is the most recent call?

How this connects

Know these first

Where this leads

You've reached the end of this thread. Try a learning path for what's next.

Part of Java from zero.

Was this lesson helpful?

Finished reading? Mark it complete to track your progress.