Appendix G · Platform Notes — NetBeans / IntelliJ IDEA¶
⌨ About This Page¶
This page is a deep reference for debugging in IntelliJ IDEA and NetBeans, with a focus on Java development. It expands on the brief orientation given in IDE-Specific Notes.
IntelliJ IDEA and Android Studio share the same underlying platform (IntelliJ Platform), so much of the IntelliJ guidance here also applies directly to Android Studio's Java/Kotlin debugging — see Appendix G · Android Studio for Android-specific additions (Logcat, Layout Inspector).
⌨ I. IntelliJ IDEA¶
The Run and Debug Output¶
Run output (bottom panel) shows console output — System.out.println(), exceptions, and program output — when running normally.
Debug output (bottom panel, when running in debug mode) shows the same console output plus the Debug tabs: Frames, Variables, Watches.
Reading a Java Exception in the Console¶
Exception in thread "main" java.lang.ArithmeticException: / by zero
at com.example.Calculator.divide(Calculator.java:14)
at com.example.Main.main(Main.java:8)
Process finished with exit code 1
In IntelliJ, lines like at com.example.Calculator.divide(Calculator.java:14) are clickable hyperlinks (shown underlined and in a different colour). Click to navigate directly to that line.
Setting Breakpoints¶
Click in the gutter to the left of the line number. A red circle appears.
Starting a debug session: Click the debug icon (bug-shaped) next to the run configuration dropdown, or right-click the file/class containing main() and select Debug.
Conditional Breakpoints¶
Right-click the breakpoint circle → a small editing panel appears directly below the line:
- Condition: any valid Java/Kotlin boolean expression, e.g.,
i == 99,user.getId().equals("usr_123") - Log message to console: print a custom message when the breakpoint is hit
- Remove once hit: automatically disable after the first trigger — useful for one-time investigation in a loop
⌨ II. The Debug Tool Window¶
When paused at a breakpoint, the Debug tool window opens with these tabs:
| Tab | Purpose |
|---|---|
| Frames | The call stack — click any frame to see that method's local variables |
| Variables | All variables in scope at the current frame — expandable for objects, arrays, collections |
| Watches | Custom expressions — click +, type any expression |
| Console | Standard output |
Stepping Controls¶
| Shortcut | Action |
|---|---|
F8 |
Step Over |
F7 |
Step Into |
Alt+Shift+F7 |
Force Step Into (steps into library/framework code, normally skipped) |
Shift+F8 |
Step Out |
F9 |
Resume Program |
Alt+F9 |
Run to Cursor |
Alt+F8 |
Evaluate Expression |
Ctrl+F8 |
Toggle breakpoint |
Ctrl+Shift+F8 |
View all breakpoints |
Force Step Into¶
By default, Step Into skips over standard library code (java.util.*, java.lang.*) to avoid stepping through code you almost never need to inspect. Force Step Into (Alt+Shift+F7) overrides this — useful in the rare case where the bug genuinely is in how a library method behaves with your specific arguments.
Inline Variable Values¶
IntelliJ displays the current value of each variable directly in the editor, as a greyed-out annotation at the end of the line, during a debug session:
This updates live as you step, giving immediate visibility without checking the Variables panel for simple cases.
Drop Frame¶
The Drop Frame button in the debug toolbar rewinds execution to the beginning of the currently selected method call — without restarting the program. If you stepped past the interesting part, Drop Frame lets you go back and step through it again with a different focus (e.g., using Step Into this time instead of Step Over).
⌨ III. Evaluate Expression¶
Alt+F8 opens the Evaluate Expression dialog. Type any valid expression in the current language, evaluated in the context of the paused frame:
order.getItems().size()
order.getTotal() > 100
items.stream().filter(i -> i.getPrice() > 50).count()
The Evaluate button shows the result immediately. The dialog can also execute statements — including ones that change object state — useful for testing a fix's effect interactively before applying it to the source.
⌨ IV. NetBeans¶
NetBeans uses similar concepts with different shortcuts and panel names.
Setting Breakpoints¶
Click in the left margin next to the line number. A red square or stop-sign icon appears.
Starting a Debug Session¶
Debug → Debug Project (Ctrl+F5), or right-click the project → Debug.
Key Windows¶
| Window | How to Open | Purpose |
|---|---|---|
| Variables | Window → Debugging → Variables | All variables in scope at the current breakpoint |
| Call Stack | Window → Debugging → Call Stack | The active call chain |
| Breakpoints | Window → Debugging → Breakpoints | All breakpoints — manage conditions and enable/disable |
| Output | Window → Output | Console output and program messages |
Stepping Controls¶
| Shortcut | Action |
|---|---|
F8 |
Step Over |
F7 |
Step Into |
Ctrl+F7 |
Step Out |
Ctrl+F5 |
Continue (Resume) |
Ctrl+F4 |
Finish Debugger Session |
Conditional Breakpoints in NetBeans¶
Right-click the breakpoint marker → Breakpoint Properties → check Condition and enter a boolean expression. Same concept as IntelliJ — pause only when the expression is true.
Evaluating Expressions¶
While paused, Window → Debugging → Evaluate Variables opens a panel where expressions can be typed and evaluated in the current context.
⌨ V. Common Java Debugging Scenarios¶
Scenario: ConcurrentModificationException¶
java.lang.ConcurrentModificationException
at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1013)
at java.base/java.util.ArrayList$Itr.next(ArrayList.java:967)
at com.example.OrderService.removeExpiredItems(OrderService.java:22)
This occurs when a collection is modified (an item added or removed) while it is being iterated with a for-each loop.
// Causes ConcurrentModificationException
for (Item item : items) {
if (item.isExpired()) {
items.remove(item); // modifying during iteration
}
}
// Fix: use an Iterator's remove() method
Iterator<Item> it = items.iterator();
while (it.hasNext()) {
Item item = it.next();
if (item.isExpired()) {
it.remove(); // safe — the iterator knows about this removal
}
}
// Or: collect items to remove, then remove after the loop
items.removeIf(Item::isExpired);
Scenario: ClassCastException¶
java.lang.ClassCastException: class java.lang.String cannot be cast to class java.lang.Integer
at com.example.DataProcessor.process(DataProcessor.java:31)
A value was cast to a type it does not actually have at runtime — common when working with raw types, Object, or deserialised data (e.g., from JSON or a generic collection without type safety).
Investigative approach: Set a breakpoint just before the cast. Use Evaluate Expression to check the actual runtime type: value.getClass().getName(). Compare with the type being cast to.
Scenario: StackOverflowError from Recursion¶
Exception in thread "main" java.lang.StackOverflowError
at com.example.TreeNode.countNodes(TreeNode.java:15)
at com.example.TreeNode.countNodes(TreeNode.java:15)
at com.example.TreeNode.countNodes(TreeNode.java:15)
... (repeats many times)
The same line repeating many times indicates infinite or excessively deep recursion. Set a breakpoint at the recursive call with a hit count condition (e.g., pause after 100 hits) to inspect the state at a deep point in the recursion — checking whether the base case condition is ever actually met.
// Missing or incorrect base case
public int countNodes(TreeNode node) {
return 1 + countNodes(node.left) + countNodes(node.right);
// Missing: if (node == null) return 0;
}
← Back to: Appendix G · Platform Notes — Visual Studio / Watch Windows
Continue to: Appendix G · Platform Notes — Web / Browser DevTools →
← Back to: Appendices Overview