Debugging Techniques
Effective debugging saves hours of development time. Master IDE debuggers, stack trace analysis, and remote debugging to quickly find and fix issues.
IDE Debugger Basics
IDEs like IntelliJ IDEA and Eclipse provide powerful debugging tools.
Debugger Controls
| Action | Shortcut (IntelliJ) | Description |
|---|---|---|
| Toggle Breakpoint | Ctrl+F8 |
Set/remove breakpoint on current line |
| Debug | Shift+F9 |
Start debugging |
| Step Over | F8 |
Execute line, don't enter methods |
| Step Into | F7 |
Enter the method being called |
| Step Out | Shift+F8 |
Exit current method |
| Resume | F9 |
Continue until next breakpoint |
| Evaluate Expression | Alt+F8 |
Run code in current context |
Types of Breakpoints
- Line Breakpoint: Pause at a specific line
- Conditional Breakpoint: Pause only when condition is true
- Exception Breakpoint: Pause when exception is thrown
- Method Breakpoint: Pause when method is entered/exited
- Field Watchpoint: Pause when field is accessed/modified
Pro Tip: Right-click a breakpoint to add conditions like
userId == 42 or list.size() > 100. This avoids
stopping on every iteration of a loop.
Reading Stack Traces
Stack traces show the sequence of method calls that led to an error.
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()"
at com.example.UserService.validateEmail(UserService.java:45)
at com.example.UserService.createUser(UserService.java:28)
at com.example.UserController.register(UserController.java:15)
at com.example.Main.main(Main.java:10)
How to Read It
- Line 1: Exception type and message
- Line 2: Where the exception occurred (start here!)
- Lines 3+: Call chain that led to the exception
- Read from top to bottom = most recent to oldest
Common Exceptions
| Exception | Likely Cause |
|---|---|
NullPointerException |
Called method on null object |
ArrayIndexOutOfBoundsException |
Invalid array index |
ClassCastException |
Invalid type cast |
NumberFormatException |
String can't be parsed as number |
ConcurrentModificationException |
Modified collection while iterating |
StackOverflowError |
Infinite recursion |
OutOfMemoryError |
Memory leak or large data |
Remote Debugging
Debug applications running on remote servers.
1. Start JVM with Debug Options
# Java 9+
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 -jar app.jar
# Java 8
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -jar app.jar
2. Connect from IDE
In IntelliJ: Run → Edit Configurations → Add New → Remote JVM Debug
- Host:
localhost(or server IP) - Port:
5005
Security Warning: Never expose debug ports in production!
Use
address=127.0.0.1:5005 for localhost-only access, or use
SSH tunneling for remote debugging.
Debugging Techniques
Binary Search Debugging
When you don't know where the bug is:
- Set breakpoint halfway through the code path
- Check if data is correct at that point
- If correct, bug is after; if wrong, bug is before
- Repeat until you find the exact location
Rubber Duck Debugging
Explain the code line by line (to a duck, colleague, or yourself). Often, you'll spot the bug while explaining.
Print Debugging (When All Else Fails)
public void processOrder(Order order) {
System.out.println("DEBUG: order = " + order);
System.out.println("DEBUG: order.items = " + order.getItems());
System.out.println("DEBUG: order.items.size = " + order.getItems().size());
// Better: Use logging with DEBUG level
logger.debug("Processing order: {}", order);
}
JVM Debugging Tools
jps - List Java Processes
$ jps -l
12345 com.example.MyApp
67890 org.gradle.launcher.daemon.bootstrap.GradleDaemon
jstack - Thread Dump
# Get thread dump (find deadlocks, blocked threads)
$ jstack 12345 > thread-dump.txt
jmap - Memory Analysis
# Create heap dump for memory analysis
$ jmap -dump:format=b,file=heap.hprof 12345
# Analyze with tools like Eclipse MAT or VisualVM
VisualVM
GUI tool for monitoring and profiling Java applications:
- Monitor CPU, memory, threads in real-time
- Profile method execution times
- Analyze heap dumps
- Take thread dumps
Common Debugging Scenarios
NullPointerException
// Java 14+ shows helpful NPE messages:
// Cannot invoke "String.toLowerCase()" because "user.getName()" is null
// Debugging approach:
// 1. Look at the line number in stack trace
// 2. Identify which variable is null
// 3. Trace back where it should have been set
// 4. Add null checks or fix the source
// Prevention:
Optional.ofNullable(user)
.map(User::getName)
.ifPresent(name -> process(name));
Infinite Loop
// Symptoms: Application hangs, 100% CPU
// Debugging:
// 1. Take thread dump with jstack
// 2. Look for threads in RUNNABLE state
// 3. Check the stack trace for loop locations
// Common causes:
while (i < list.size()) {
// Forgot to increment i!
process(list.get(i));
i++; // Don't forget this!
}
Summary
- Master IDE debugger shortcuts for efficiency
- Use conditional breakpoints to stop only when needed
- Read stack traces from top to bottom
- Use remote debugging for server issues (securely!)
- Use JVM tools (jstack, jmap) for production issues
- Binary search to narrow down bug location
Enjoying these tutorials?