IDEA调试技巧
在开发中,排查Bug往往比写代码更耗费时间。很多同学调试还停留在“在代码里写System.out.println,重启应用,看控制台”的原始时代。这种方式不仅低效,而且会污染代码,甚至因为重启环境导致Bug难以复现。
IntelliJ IDEA 的调试器远比你想象的更强大。它不仅是一个“暂停/继续”的工具,更是一个可以动态执行代码、实时监控变量、非侵入式打印日志的“代码CT机”。本文将带你掌握那些让你事半功倍的高级调试技巧。
1. 计算器模式:Alt + F8 的妙用
在断点暂停时,我们经常需要查看某个复杂表达式的值。虽然Variables面板可以查看变量,但如果想看user.getAddressList().get(0).getCity()这样的表达式呢?
技巧:使用 Evaluate Expression (Alt + F8)
- 操作: 在调试窗口,点击工具栏的
Evaluate Expression按钮(计算器图标)或直接按Alt + F8。 - 功能:
- 执行任意代码:你可以在弹出的输入框中执行任何合法的Java代码,而不仅限于查看变量。例如,你可以执行
user.setAge(20)来动态改变当前运行时的变量值,从而测试不同分支逻辑 。 - 代码片段模式:点击
Code Fragment Mode按钮,你可以编写多行代码,甚至定义新的局部变量和循环,用来模拟复杂的数据处理逻辑 。 - 无需打印:再也不需要为了看一个值而添加
log.info并重启服务了。
- 执行任意代码:你可以在弹出的输入框中执行任何合法的Java代码,而不仅限于查看变量。例如,你可以执行
2. 监控的艺术:Watches 与内联视图
当你断点在多个方法间跳转时,Variables面板的内容会随着栈帧变化。如果你想持续关注某个特定变量或表达式的变化,就需要用到 Watches。
- Watches 面板:在Debug窗口找到
Watches标签,点击加号添加表达式,如"当前用户名:" + user.getName()。无论你执行到哪一行,只要在作用域内,Watches 面板都会实时显示这个表达式的值 。 - 内联调试(Inline Debug):这是IDEA很贴心的一个功能。在调试时,你无需查看任何面板,代码紧挨着每一行的地方会直接以灰色字体显示当前行涉及变量的值。如果想更清晰地看到所有值,可以点击工具栏的 Show Values Inline 按钮(或右键点击行号区域选择)。
3. 断点即日志:非侵入式追踪(Evaluate and log)
这是最强大的“黑科技”之一。你是否遇到过这种情况:生产环境无法打断点,测试环境断点一停就超时?我们其实可以在不暂停程序的情况下,利用断点打印日志。
操作步骤:
- 在代码行号处打上断点。
- 右键点击断点(或按住Shift键点击断点)进入断点属性设置界面。
- 取消勾选
Suspend(这意味着代码执行到这里不会暂停)。 - 勾选
Log evaluated expression,并在输入框中输入你要打印的表达式,例如:"进入订单处理,订单ID:" + orderId + ",金额:" + amount。 - (可选)勾选
Log message to console可以打印简单的“已到达断点”消息。
效果: 再次以Debug模式运行,你会发现控制台会输出你定义的日志信息,但程序本身一直在全速运行,没有中断 。
这一招在排查循环问题时尤其好用,比如在循环体设置不暂停断点,打印每次循环的变量值,相当于动态插桩。
4. 断点的高阶属性:条件与异常
4.1 条件断点
在一个循环了1000次的循环中,你只想在第999次时停下来查看情况。难道要一直按“继续”吗?
解决方案: 右键点击断点,在 Condition 框中输入 i == 999。只有当表达式为真时,断点才会生效 。
4.2 异常断点
有时候Bug会抛出异常,但我们不知道异常到底在哪一行抛出的。
解决方案: 点击 View Breakpoints 按钮(或按 Ctrl+Shift+F8),点击加号添加 Java Exception Breakpoints。输入你要捕获的异常类名(如 NullPointerException)。此后,一旦代码中抛出该异常,IDEA会自动定位到抛出异常的那一行(即使你没有在那行设置断点)。
5. 多线程调试:断点只停你想停的线程
调试多线程程序时,如果多个线程都命中了同一个断点,调试器会在多个线程之间疯狂跳转,导致你无法看清单个线程的执行流程。
解决方案:
右键点击断点,在 Suspend 选项中,选择 Thread 而不是默认的 All。
All:所有线程遇到该断点都会暂停。Thread:只有当前命中断点的线程暂停,其他线程继续运行 。
这样你就可以安心地跟踪一个线程的执行路径,而不会被其他线程干扰。
6. 进阶必知:Drop Frame 与 强制返回
- Drop Frame (回退断点):当你单步跟踪进入了一个方法,发现走错了,想退回去重新执行?点击调试栈帧上的 Drop Frame 按钮(类似于“撤销”的图标)。它会让你丢弃当前栈帧,回退到调用该方法的地方,并且变量状态也会回退,相当于“时间回溯” 。
- Force Return (强制返回):你正在调试一个循环,已经找到了问题所在,不想再执行后续无用的代码了。右键点击栈帧,选择
Force Return,可以强制当前方法返回指定的值,提前结束执行。
7. 扩展:远程调试
线上出了问题,但测试环境复现不了?只要你部署的代码和本地代码一致,就可以进行远程调试。
- JVM启动参数:在远程服务器上启动Java程序时,加上特定的调试参数(如
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005) 。 - IDEA配置:在
Edit Configurations中添加一个Remote配置,填写服务器的IP和调试端口(如5005)。启动Debug模式,IDEA就会连接到远程服务器。此时你在本地下的断点,就能拦截远程服务器的请求 。
总结
熟练使用IDEA的调试工具,可以从根本上改变排查问题的效率。
- 用
Alt+F8动态探索代码; - 用
Watches持续盯梢关键数据; - 用非挂起断点实现零侵入日志;
- 用条件断点和异常断点实现精准打击。
希望这些技巧能帮助你从繁琐的 System.out 和重启中解放出来,让调试成为一种享受。
参考资料
- IntelliJ IDEA 官方帮助文档 - 调试代码
- IntelliJ IDEA 调试器技巧:Watches 与表达式求值
- 条件断点与异常断点的高级应用
- 多线程调试中的线程断点控制