挖掘IntelliJ IDEA的调试功能
- 1. 断点
- 2. 调试技巧
- 2.1. 智能进入(Smart step into)
- 2.2. 表达式评估(Evaluate expression)
- 2.3. 远程调试(Remote debug)
- 2.4. 弃栈帧(Drop frame)
- 2.5. 强制抛异常(Throw an exception):
- 2.6. 强制返回(Force return):
- 2.7. 自动载入变化代码(Reload changes)
- 2.8. 显示方法返回值(Show method return values)
- 2.9. 调试流(Trace Current Stream Chain)
- 2.10. 调试内存泄漏(Memory View)
- 2.11. 调试lombok
- 2.12. 其它
- 3. 快捷键
本文介绍了IntelliJ IDEA的一些相对不那么广为人知,但是又很实用的调试功能。希望能让你的IDE发挥出最大的功效!本文使用的IDEA版本是2018.1
社区版,快捷键是Mac OS X
。本文的兄弟篇是挖掘IntelliJ IDEA的实用功能。
断点
断点类型
一般来说调试时,我们都是在代码行上鼠标一点,然后运行测试,遇断点所在的行即停,这就是所谓的行断点。IDEA支持以下几种断点类型:
- 行断点(Line Breakpoints):就是我们最经常用的方式。
- 方法断点(Method Breakpoints):如果你看到代码调用了一个接口,但不知道具体会跑在哪个实现上,便可以在接口上设置断点,这样不管哪个子类运行到这个方法都会停下来。
- 异常断点(Exception Breakpoints):可以在Run -> View Breakpoints中的Java Exception Breakpoints里添加异常的具体类型。这样的话,程序中一旦发生了这种异常马上就会停下来。
- 字段断点(Field Watchpoints):可以设置在字段上,这样读写字段都可以触发。需要注意的是,默认只有写才会停下,想要让读取时也停下,需要右击断点,在Watch的Field access上打勾才行。
条件断点
断点是可以设置条件的,这样便可以只在关心的时候停下来。比如说循环里处理一堆字符串,但是只关心特定的字符串,那条件断点便可以派上用场。按住Shift键设置断点,或是右击断点之后选择More来打开以下界面:
上图就是设置条件断点的界面,直接在Condition里输入条件即可,如"ggg".equals(name)
。需要注意的是,Suspend默认是没有打勾的,必须勾选上才能让程序暂停。另外,辛辛苦苦设置的特定断点,是可以拖拽到别的地方去的,这样就省的到处敲来敲去的了。还有一个小技巧是按住Alt的同时设置断点,可以让断点仅停一次便自动消失。在设置临时断点时有点用。
无断点暂停
如果在很长的循环时不知道程序运行到哪里了,可以在调试时点击调试窗口上的Pause Program,这样程序便能在当前执行的地方暂停。另外,运行到光标(Run to cursor)也可以在没有设置断点的时候让程序运行到光标所在行时暂停。
调试技巧
下面介绍一些调试的小技巧。
智能进入(Smart step into)
当调试程序运行到类似这样的句子时,如果你想看的是actor.action
方法,那么进入这个方法就相对麻烦一些。
这时可以使用调试窗口上的智能进入,程序会弹出一个对话框,我们选择需要的调用处即可。算是一个提升调试效率的小技巧。
官方文档传送门:https://www.jetbrains.com/help/idea/debugging-code.html#d181035e286
表达式评估(Evaluate expression)
这应该是大部分人都知道的技巧了,可以通过表达式评估来重新赋值当前的变量,以便让程序运行到其它的分支去。当然也可以在Variables窗口中,右击想要改变的变量,选择Set Value。不过表达式评估里可以轻松增加新变量、动态import新类库等,功能更加强大。
官方文档传送门:https://www.jetbrains.com/help/idea/evaluating-expressions.html
远程调试(Remote debug)
如果运行的实例在其它机器(或者虚拟机、docker)上,只要实例设置了以下参数,就可以通过远程调试连接到8000
端口进行调试。
官方文档传送门:https://www.jetbrains.com/help/idea/debugging-code.html#d181035e408
对于IDEA来说,只需要在Run -> Edit Configuration里,增加一个Remote,设置主机Host和端口Port,然后调试它即可。
弃栈帧(Drop frame)
Visual Studio好的一点是调试时可以拖拽当前执行的位置,方便反复查看。虽然IDEA没有这样的功能,但是它可以使用弃栈帧来把当前调用栈的第一栈帧丢弃掉,相当于重新开始当前调试的方法。使用方法也算简单,在要丢弃的栈帧上右击,选择Drop Frame即可。或者直接单击调试窗口的Drop Frame按钮。不过需要注意的是,如果对象在子方法运行时发生了变化,是不会再变回去的。
官方文档传送门:https://www.jetbrains.com/help/idea/debugging-code.html#d181035e308
强制抛异常(Throw an exception):
这是IDEA 2018年加入的新功能,可以直接在调试中抛出指定的异常。使用方法跟上面的弃栈帧类似,右击栈帧并选择Throw Exception,然后输入如下代码即可:
官方文档传送门:https://www.jetbrains.com/help/idea/altering-the-program-s-execution-flow.html#throw_exception
强制返回(Force return):
这是IDEA2015版时增加的功能,类似上面的手动抛异常,只不过是返回一个指定值罢了。使用方法跟上面也都类似,右击栈帧并选择Force Return,然后输入要返回的值即可。如果是void
的方法那就更简单了,连返回值都不用输。
官方文档传送门:https://www.jetbrains.com/help/idea/altering-the-program-s-execution-flow.html
自动载入变化代码(Reload changes)
利用Java虚拟机提供的HotSwap功能,我们可以做到一边调试一边改代码。只要在修改完代码之后,点击Run -> Reload Changed Classes即可。不过HotSwap有一些限制,例如不支持static的字段和方法等。
官方文档传送门:https://www.jetbrains.com/help/idea/altering-the-program-s-execution-flow.html#reload_classes
显示方法返回值(Show method return values)
调试窗口里的Settings -> Show Method Return Values开关可以显示方法的返回值。例如以下方法:
只要在return
上设断点然后Step Over,或者在方法内部的任何地方设断点然后Step Out一下,便可以在调用处的变量窗口看到一个类似于这样的值:Test.random() = 0.28735657504865864
。在这个方法调用没有赋值给变量时(如if (random() < 10)
)还挺有用的。
调试流(Trace Current Stream Chain)
前面说了Visual Studio的好,但是它调试时不能看lambda的值也真是挺恶心的,据说2015版以后开始支持有限的lambda了。IDEA在这方面就做的非常到位。Java 8带来的Stream里面到底是什么,有时候很难知道。通过IDEA提供的这个功能,我们可以很轻松地看到流在各个步骤之间的变化。如下图:
展平模式(Flat Mode)更是提供了全局的视角:
使用这个功能也非常简单,当程序在lambda表达式的任意处停下时,单击调试窗口的Trace Current Stream Chain按钮即可。
官方文档传送门:https://www.jetbrains.com/help/idea/analyze-java-stream-operations.html
调试内存泄漏(Memory View)
内存泄漏是一个比较头疼的问题,好在IDEA提供了内存分析工具,只要单击调试窗口右上角的Restore ‘Memory’ View就能看到内存窗口,然后点击其中的Click to load the classes list就能看到当前内存的对象分布情况。然后可以据此分析到底是哪个类的对象数量看起来有问题。
官方文档传送门:https://www.jetbrains.com/help/idea/analyze-objects-in-the-jvm-heap.html
调试lombok
如果只是想暂停一下set或get方法,可以使用字段断点,只不过可能会在调试中报错:Source code does not match the bytecode,但它能够工作。
如果想设断点的是toString
、hashCode
等方法,可以在注解上设置断点,也可以在调试时使用:Refactor -> Delombok并选择相对应的注解,然后再使用上文介绍的HotSwap功能,就可以生成代码并按需调试了。最后别忘记把代码恢复回来。
其它
调试异步、线程、死锁、活锁等高级功能,官网上面有详细的教程,可以在用到时参考。
官方文档传送门:https://www.jetbrains.com/help/idea/tutorial-java-debugging-deep-dive.html
快捷键
功能熟悉了以后,熟练使用快捷键能够大幅提高效率。以下是笔者调试时经常使用的快捷键:
- F7:进入调用的方法
- F8:单步运行
- F9:继续运行
- Shift+F7:智能进入调用的方法
- Shift+F8:跳出当前方法
- Alt+F8:表达式评估
- Alt+F9:运行到光标
- Ctrl+Shift+F9:调试当前光标所在方法或类
- Ctrl+Shift+F10:运行当前光标所在方法或类
- Shift+F9:调试上次运行的测试
- Shift+F10:运行上次运行的测试
- Command+Shift+T:切换测试和实现