نقاط التوقف والتنقّل خطوة بخطوة
في هذا الدرس 11 موضوعات
هذا الدرس متاح حاليًا باللغة الإنجليزية فقط، ولم تُنشر نسخته العربية بعد.
Lesson Overview
In the last lesson you learned the debugging method: reproduce, isolate, hypothesize, test, fix, verify. The "test" step often means looking at what the program knows while it runs. Printing values does that, but it clutters your code and you must guess in advance what to print. A debugger lets you freeze a running program and look around.
Our detective's picture: a breakpoint is a police tape put across one line of the program. When the program reaches the tape, it stops, and you can examine the scene. Stepping is walking through the scene one line at a time.
Why this matters: knowing how to pause and step is the most-used debugging skill in a Java job. It works the same way for a ten-line exercise and for a large backend service, and it is the basic skill behind the module's final live demonstration.
This lesson builds on the debugger glimpses in BEG-013-L07 and BEG-014-L08, loops from BEG-013, and the call stack from BEG-014-L05. It uses IntelliJ IDEA; menus and shortcuts vary between versions and keymaps, so check yours.
Learning Objectives
By the end of this lesson you will be able to:
- Set and remove a line breakpoint, and start the program in debug mode.
- Explain that a program pauses before the breakpoint's line runs.
- Use step over, step into, step out, and resume, and say when to choose each.
- Set a conditional breakpoint that pauses only for a chosen iteration.
- Use a breakpoint, not a print, to find where a loop or method call goes wrong.
- Avoid the common traps: running instead of debugging, and stepping too far.
Written Explanation
Breakpoints
A breakpoint marks a line where the debugger should suspend the program. In IntelliJ IDEA you click in the left margin (the gutter) beside a line, and a red dot appears. The official IntelliJ documentation also describes placing the caret on the line and pressing Ctrl+F8. Click the dot again to remove it.
Two rules that trip up beginners:
- The program pauses before the marked line runs. At that moment the line has not yet executed, so any change it makes is not visible yet.
- You must put the breakpoint on a line that actually executes. Blank lines, comments, and lines with only a closing brace are not good targets; a breakpoint on a line the program never reaches never fires.
Starting in debug mode
A breakpoint only works when the program is started with the Debug command (the bug-shaped button beside the green Run triangle, or the matching entry in the run menu), not plain Run. When a breakpoint is hit, IntelliJ opens the Debug tool window. The IntelliJ documentation lists its tabs: Frames (the call stack), Variables, Watches, and Console, with a toolbar for stepping. The line about to run is highlighted in the editor.
If the program finishes without ever stopping, one of these is true: you used Run, the breakpoint is on a line that was never reached, or the breakpoints are muted. The Mute Breakpoints button on the debug toolbar switches them all off without ending the session, and clicking it again turns them back on.
Moving through the code
Once paused, you choose how to continue. These are the four moves you need. The IntelliJ documentation describes the behavior of each; the shortcut keys below are the usual defaults, but they were not stated on the documentation pages consulted for this lesson, so confirm them in your IDE by hovering over the toolbar buttons.
| Move | Typical key | What it does |
|---|---|---|
| Step over | F8 | Runs the current line and pauses on the next one. If the line calls a method, the whole call runs as one step. |
| Step into | F7 | If the line calls a method, enters it and pauses on its first line. IntelliJ skips library code by default, such as standard Java classes. |
| Step out | Shift+F8 | Runs until the current method returns to its caller. |
| Resume | F9 | Runs on until the next breakpoint, or the end of the program. |
The documentation also notes that step over still stops at a breakpoint inside a method the line calls. Run to Cursor (Alt+F9, per the documentation) runs to the line where your caret is, which is quicker than setting a breakpoint for one visit.
Which move, when?
Use these rules:
- The line calls a method that you suspect is wrong: step into.
- The line calls a method that you trust (or that is library code): step over.
- You went into a method by mistake or have finished looking: step out.
- You want to skip to the next interesting stop: resume.
The classic mistake is stepping over the very line that holds the bug. If the state is wrong after a step, restart and step into the call you stepped over.
Conditional breakpoints
A breakpoint inside a loop stops on every pass. For a loop with 100 passes that is tedious. A conditional breakpoint stops only when a boolean expression is true. In IntelliJ, right-click the line and choose Add Conditional Breakpoint, or right-click an existing breakpoint, then type a condition such as i == 50. The documentation says the condition must be valid at the breakpoint's line, and warns that conditions can have side effects, so keep them to simple comparisons.
Examples of useful conditions:
i == 50: stop on one specific pass.values[i] < 0: stop when a data value is unexpected.name == null: stop only when something is missing. (For text comparison, use.equals, as in BEG-009.)
Print versus breakpoint
A temporary System.out.println is fine for a quick check, but you edit code (and can forget to remove the line), must guess the right variable in advance, and cannot look around the value. A breakpoint shows every variable at once without recompiling. Print statements everywhere is a classic beginner habit to outgrow.
Examples
Example 1: pause once and read the state (simple)
public class Loop {
public static void main(String[] args) {
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
}
System.out.println(sum);
}
}The program prints 5050. Put a breakpoint on sum += i; and start in Debug mode. The program pauses on the first pass, before the line runs. The Variables tab shows sum = 0 and i = 1. Step over once: the highlight moves on and the Variables tab now shows sum = 1. Resume, and the program stops again with i = 2 and sum = 1; the breakpoint is hit once per pass.
What you learned: the breakpoint stops before the line, so after a single step sum has absorbed the value. This is the same reading of state you did by hand with a variable table in BEG-016.
Example 2: step into, over, and out (practical)
static int addTax(int price) {
int tax = price / 10;
return price + tax;
}
public static void main(String[] args) {
int[] prices = {100, 250, 40};
int total = 0;
for (int i = 0; i < prices.length; i++) {
int withTax = addTax(prices[i]);
total += withTax;
}
System.out.println("Total: " + total);
}The program prints Total: 429 (110 + 275 + 44). Put a breakpoint on int withTax = addTax(prices[i]);.
- The program pauses on that line with
i = 0,total = 0. Press step into: the highlight jumps intoaddTax, onint tax = price / 10;, and the Frames tab showsaddTaxabovemain: the call stack from BEG-014-L05, now visible. - Step over once:
tax = 10appears and the next line is thereturn. - Step out: the method finishes and you are back in
main, on the call line or just after it (the exact stopping point depends on the IDE version), withwithTaxabout to be stored as110. - On the next pass, if you trust
addTax, step over the call line: the call runs as one step.
What you learned: stepping into follows the same call stack your program builds, so you can walk down and back up it.
Example 3: a conditional breakpoint in a long loop (realistic)
static int firstNegativeIndex(int[] values) {
for (int i = 0; i < values.length; i++) {
if (values[i] < 0) {
return i;
}
}
return -1;
}Suppose data holds 200 numbers (data[i] is i * 3, except data[149] = -5) and the program prints 149. You want to watch what the loop sees near that index. A plain breakpoint on the if would stop 150 times. Instead, right-click the line, add the condition i >= 140, and run in Debug mode. The program first stops with i = 140. Step over a few passes while watching values[i]: at i = 149 it is -5, and the return i; line runs. The real run printed 149. A condition turns 150 stops into the one you need.
Backend Insight
IntelliJ and similar IDEs can attach a debugger to a program that is running in another process, such as a small web service on your own computer, and pause its threads at your breakpoint. That is how backend developers inspect what a request handler was doing when it misbehaved. In busy services, pausing a thread can hold up the request, so developers use conditional breakpoints (for example, only for one user id) instead of stopping every request. Pausing a shared production service is generally avoided; there, logs and monitoring are the tools, which come later. The habit you build here, pause precisely and look at state, carries over.
Common Mistakes
Mistake 1: Using Run instead of Debug
Breakpoints are ignored by a normal run. Start the program with the Debug command.
Mistake 2: Expecting the marked line to have run
The program stops before the line. Step once to see its effect.
Mistake 3: Stepping over the bug
If the state looks right before a line and wrong after it, the bug is in that line or something it calls. Restart and step into the call.
Mistake 4: Stepping through hundreds of passes
Use a conditional breakpoint or Run to Cursor to reach the interesting pass.
Mistake 5: Leaving breakpoints behind or muted
If the debugger never stops, check the mute button first.
Exercises
Try each exercise yourself before opening the solutions. Use your own IntelliJ project for B and C.
Level A: Foundation
A1. A breakpoint is on the line count++;. Has count been increased when the program first pauses there?
أظهر الحل A1
A1. No. The program pauses before the line runs, so count still has its old value.
A2. Name the move for each: (a) enter the method being called; (b) run the current line and go to the next; (c) leave the current method; (d) run to the next breakpoint.
أظهر الحل A2
A2. (a) Step into. (b) Step over. (c) Step out. (d) Resume.
A3. The program runs to the end and never pauses. Give two possible causes.
أظهر الحل A3
A3. You started with Run and not Debug; the breakpoint is on a line that is never reached; breakpoints are muted; the breakpoint is on a non-executable line.
Level B: Application
B1. Write the simple loop for (int i = 1; i <= 100; i++) { sum += i; } in your project. Set a conditional breakpoint that stops only when i is 50, and report the value of sum at that stop.
أظهر الحل B1
B1. The condition is i == 50. When the program pauses, i is 50 and the line sum += i; has not run yet, so sum is the total of 1 to 49, which is 1225. After one step over, sum is 1275.
B2. In the addTax program above, give two different sequences of moves that take you from the breakpoint on the call line to the line total += withTax; for the first item, and say what withTax is when you arrive.
أظهر الحل B2
B2. (1) Step into, then step out, then step over if the pause is still on the call line; or (2) simply step over the call line: the call runs as one step. Either way you arrive at total += withTax; with withTax = 110 (100 plus tax 10).
B3. Your loop sums the numbers 1 to 10, and sum ends up wrong. You pause at a breakpoint inside the loop and step over the line sum = add(sum, i);. Afterwards sum is wrong. What do you do next?
أظهر الحل B3
B3. Restart the session, and this time step into add, because the state became wrong during that line. Inspect sum and i as add receives them and the value it returns. Stepping over a call hides what happens inside it.
Level C: Challenge
C1. Write a loop over an array of 1,000 numbers. Make exactly one value negative. Show the condition you would use on a breakpoint to stop on it without knowing its position, and explain why that is better than a print.
أظهر الحل C1
C1. Condition: values[i] < 0 (assuming the loop variable is i; the breakpoint must be on a line inside the loop). The debugger stops on exactly one pass, without you counting to the position, and you can inspect other variables at the same moment. A print would show only the value you chose in advance and needs a code edit.
C2. Step into pauses inside a method, and the Frames tab shows two frames. Using what you know from BEG-014-L05, explain what each frame contains and which is on top.
أظهر الحل C2
C2. The top frame is the method you stepped into: its parameters and locals. The frame below belongs to the caller (for example main), paused at the line of the call. The top frame is the current one; the one below is waiting for it to return.
Mini Challenge
Take the Level B loop and make it count the numbers from 1 to 100 that are divisible by 7. Without printing anything:
- Set a conditional breakpoint that stops only when
i % 7 == 0. - Resume repeatedly and write down the value of your counter at the first three stops.
- Use step into on a small method of your own (for example one that returns whether a number is divisible by 7) to see the Frames tab show two frames.
Check your work: the debugger stops 14 times in total, and your counter at the first three stops matches what you traced by hand.
Summary & Next Lesson
Key takeaways
- A breakpoint pauses the program before its line runs; use the Debug command to make it work.
- Step over runs a line, step into enters the called method, step out leaves the current method, and resume runs to the next breakpoint.
- Step into the call when you suspect the bug is inside it; step over code you trust.
- A conditional breakpoint stops only when its condition is true, which saves hundreds of stops in a loop.
- A breakpoint shows all variables at once, so it usually beats a print.
Next lesson
Pausing is only half the job. The next lesson, "Variables, watches, and evaluate expression", shows what to look at once the program is paused and how to find where its state first goes wrong.
Self-check
- Does the program pause before or after the breakpoint's line runs?
- What is the difference between step over and step into?
- When would you use step out?
- What does a conditional breakpoint do?
- Why do breakpoints sometimes seem to do nothing?
أظهر الإجابات
- Before.
- Step over runs a method call as one step; step into enters the called method.
- When you have finished looking inside a method and want to return to its caller.
- It pauses only when its condition is true.
- The program was run, not debugged; the line is never reached; or the breakpoints are muted.
References
- JetBrains, Stepping through the program. Supports the behavior of step over, step into (skipping library code by default), step out, and Run to Cursor (Alt+F9). It does not list the F7, F8, Shift+F8, or F9 shortcuts, so those are stated as typical defaults to confirm in your IDE.
- JetBrains, Breakpoints. Supports gutter and Ctrl+F8 line breakpoints, conditional breakpoints (right-click, Add Conditional Breakpoint), the side-effect warning, and muting.
- JetBrains, Debug tool window. Supports the Frames, Variables, Watches, and Console tabs and the Mute Breakpoints button on the toolbar. Its Resume (F9) and stepping shortcuts came from the module notes and were not stated on the page.
- The program outputs (
5050,Total: 429,149) come from compiling and running the code with JDK 21. The description of what each debugger session shows was derived from the code and the documentation above, not from a recorded IDE session.
التطبيق
طبّق هذا الدرس بمختبر الوحدة وتمارينها واختبارها.
تعليم الدرس كمكتمل اختياري ويمكنك التراجع عنه في أي وقت. يبقى تقدمك محفوظًا في هذا المتصفح.