1. Bug
程序员有自己的黑话。你将深入接触的第一个词是 Bug(源自英语的 bug — 虫子)。这个词指的是程序中的错误,导致它行为异常、崩溃或输出奇怪的结果。
如果程序运行得很奇怪,但程序员坚持说这就是设计初衷,人们通常会说:“这不是 Bug,这是 Feature。”网上充满了关于这个话题的表情包。
历史背景
传说在 1947 年 9 月,哈佛的科学家们在测试 Mark II 计算机时,它发生了故障。检查了所有触点后,他们发现一只真正的飞蛾卡在了继电器之间。这只昆虫被贴在日志里,旁边写着“First actual case of bug being found”(第一个实际发现的虫子案例)。
从那时起,寻找和排除错误的过程就被称为 Debug 或调试。

2. Debug Mode
为了找出错误,程序员使用 Debugger。这是 IntelliJ IDEA 内部的一个特殊工具,允许你暂停程序的执行,查看其“引擎盖下”的状况。
Intellij IDEA 可以以两种模式运行你的程序:
| 模式 | 图标 | 快捷键 | 含义 |
|---|---|---|---|
| Run(普通) | |
Shift+F10 (Win/Lin)Ctrl+R (Mac) |
程序从头到尾直接运行。 |
| Debug(调试) | |
Shift+F9 (Win/Lin)Ctrl+D (Mac) |
程序可以在指定位置停止。 |
在调试模式下,你可以 逐行 执行程序,观察变量值的变化。
3. 断点 (Breakpoints)
为了让 Debugger 知道在哪里停止,你必须设置一个 Break Point。如果没有它,程序会像往常一样直接飞速运行到底。
让我们用一个实际例子来练习。我们将乘法逻辑提取到一个独立的方法中,以展示调试器的强大威力。将这段代码复制到 IDEA 中:
public class Main {
public static void main(String[] args) {
int sum = 0;
for (int i = 1; i <= 5; i++) {
int result = calculateMultiply(i); // <--- 我们想在这里停止
sum += result;
System.out.println("Step: " + i + ", Result: " + result + ", Sum: " + sum);
}
System.out.println("Final Sum: " + sum);
}
public static int calculateMultiply(int number) {
return number * 2;
}
}
任务。 我们想看看变量在循环内是如何变化的,并查看我们方法内部的情况。
操作。 用鼠标点击 int result = calculateMultiply(i); 这一行左侧的窄灰色条。会出现一个红色的圆圈。
现在通过 Debug(虫子图标)运行程序。程序将启动并在执行这一行之前瞬间“冻结”。
4. 控制:F8, F7, F9
当程序暂停时,在 Debugger 面板的顶部有一个控制台。
F8 — 步过 (Step Over)
按下 F8。程序将执行当前行(调用方法,获取结果),并移动到下一行 sum += result;。
再次按下 F8。程序将数字相加。你将看到变量的值发生了变化。
再次按下 F8。你将看到控制台的输出。
这是基本的移动方式:逐行执行,不深入方法的内部细节。
F9 — 恢复程序 (Resume Program)
我们的循环从 1 到 5。按五次 F8 跑完一圈循环太慢了。如果循环有 1000 次迭代呢?
按下 F9。程序将“解冻”,执行当前迭代中剩余的所有代码,进入第二圈,然后... 再次在 Breakpoint 处停止。
因此,使用 F9 你可以快速滚动循环:按一次 — 一次迭代。
F7 — 步入 (Step Into)
如果在代码中遇到对你方法的调用(在我们的例子中是 calculateMultiply(i)),你按下 F8,Debugger 只会执行它并继续。但是,如果你想看看这个方法 内部 的代码是如何工作的 — 请按 F7。
当程序停在 int result = calculateMultiply(i); 这一行时,尝试按下 F7。Debugger 会将你带入 calculateMultiply 方法的内部,你会看到值是如何传递给参数 number 的。
Shift + F8 — 步出 (Step Out)
如果你在 System.out.println(...) 这一行不小心按了 F7 并进入了 Java 系统代码的深渊该怎么办?阅读数千行别人的代码既无聊又难懂。
按下 Shift + F8。程序将快速执行当前方法中剩余的所有内容,并带你回到你来的地方(进入你的 main 方法)。
5. 在哪里查看值?
回到我们包含循环的例子。
方法 1: Inline Debugging
直接看代码编辑器。在代码行的右侧,IDEA 会用灰色显示当前值。
方法 2: Variables 面板
在 Debugger 窗口底部有一个 Variables 选项卡。它显示了所有当前的变量。
对于 Java 的一个重要说明: 基本类型(例如 int)直接显示它们的值。但是对象和数组(例如 String[])内部存储了大量数据。要查看它们的内容,你需要点击变量左侧的小箭头来“展开”对象。
方法 3: Frames 面板
在变量的左侧有一个列表,称为 Frames(调用栈)。它显示了程序当前处于哪个步骤。
例如,条目 main:6, Main 意味着:
- 你在 Main 类的 main 方法中。
- 你停在第 6 行。
这是你在代码中的精确地址。如果你进入了另一个方法(在 calculateMultiply 上按 F7),这个列表中会出现一条新记录 calculateMultiply:13, Main 在顶部,表明新方法是从上一个方法中调用的。
6. Evaluate Expression
有时候只看变量是不够的。你想问:“如果...会怎样?”
按下 Alt + F8 (Windows/Linux) 或 Option + F8 (macOS)。将打开 "Evaluate" 窗口。你也可以直接在 Variables 面板下方的行中输入表达式。
在这里,你可以使用当前变量编写任何代码。例如,在我们的循环中输入:
sum + 100
按下 Enter,IDEA 将计算结果,而不会改变真实的程序。这是你用于实验的草稿本。
7. 条件断点 (Conditional Breakpoints)
想象一下,你有一个 10,000 次迭代的循环,而错误只发生在第 5,000 步。按五千次 F9 是个坏主意。
右键单击 红色的 Breakpoint 圆圈。将出现一个弹出窗口。在 Condition 字段中写入一个 Java 条件,例如:i == 5。点击 Done。
现在,如果你启动 Debugger,程序将忽略前 4999 圈,并且仅在条件变为 true 时才停止。这将为你节省数小时的工作时间!
8. 管理所有断点
有时初学者会在项目的不同文件中设置太多的 Breakpoints,导致程序后来在意想不到的地方不断停止。手动在所有文件中寻找红圈很费时间。
按下 Ctrl + Shift + F8 (Windows/Linux) 或 Cmd + Shift + F8 (macOS)。将打开 Breakpoints 窗口。
在这里,你可以看到项目中所有断点的列表。你可以取消选中它们(暂时禁用)或使用 Delete 键将其删除。
9. 总结
我们已经回顾了 Java 开发者寻找错误的主要武器库。调试器 (Debugger) 是将编写代码从“占卜”转变为精确工程工作的东西。
在商业开发中,快速找到错误原因的能力甚至比快速编写代码的能力更有价值。练习使用条件断点和 Evaluate Expression,没有一个 Bug 能逃脱你的眼睛。
GO TO FULL VERSION