本文介绍了 IntelliJ IDEA 的一些相对不那么广为人知,但是又很实用的调试功能。希望能让你的IDE发挥出最大的功效!本文使用的IDEA版本是 2018.1
社区版,快捷键是 Mac OS X
。本文的兄弟篇是 挖掘IntelliJ IDEA的实用功能 。
一般来说调试时,我们都是在代码行上鼠标一点,然后运行测试,遇断点所在的行即停,这就是所谓的行断点。IDEA支持以下几种断点类型:
断点是可以设置条件的,这样便可以只在关心的时候停下来。比如说循环里处理一堆字符串,但是只关心特定的字符串,那条件断点便可以派上用场。按住Shift键设置断点,或是右击断点之后选择 More 来打开以下界面:
上图就是设置条件断点的界面,直接在 Condition 里输入条件即可,如 "ggg".equals(name)
。需要注意的是, Suspend 默认是没有打勾的,必须勾选上才能让程序暂停。另外,辛辛苦苦设置的特定断点,是可以拖拽到别的地方去的,这样就省的到处敲来敲去的了。还有一个小技巧是按住Alt的同时设置断点,可以让断点仅停一次便自动消失。在设置临时断点时有点用。
如果在很长的循环时不知道程序运行到哪里了,可以在调试时点击调试窗口上的 Pause Program ,这样程序便能在当前执行的地方暂停。另外,运行到光标(Run to cursor)也可以在没有设置断点的时候让程序运行到光标所在行时暂停。
下面介绍一些调试的小技巧。
当调试程序运行到类似这样的句子时,如果你想看的是 actor.action
方法,那么进入这个方法就相对麻烦一些。
actor.action(actionProvider.provide(action.getName()));
这时可以使用调试窗口上的智能进入,程序会弹出一个对话框,我们选择需要的调用处即可。算是一个提升调试效率的小技巧。
官方文档传送门: https://www.jetbrains.com/help/idea/debugging-code.html#d181035e286
这应该是大部分人都知道的技巧了,可以通过表达式评估来重新赋值当前的变量,以便让程序运行到其它的分支去。当然也可以在 Variables 窗口中,右击想要改变的变量,选择 Set Value 。不过表达式评估里可以轻松增加新变量、动态import新类库等,功能更加强大。
官方文档传送门: https://www.jetbrains.com/help/idea/evaluating-expressions.html
如果运行的实例在其它机器(或者虚拟机、docker)上,只要实例设置了以下参数,就可以通过远程调试连接到 8000
端口进行调试。
-Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=y
官方文档传送门: https://www.jetbrains.com/help/idea/debugging-code.html#d181035e408
对于IDEA来说,只需要在 Run -> Edit Configuration 里,增加一个 Remote ,设置主机 Host 和端口 Port ,然后调试它即可。
Visual Studio好的一点是调试时可以拖拽当前执行的位置,方便反复查看。虽然IDEA没有这样的功能,但是它可以使用弃栈帧来把当前调用栈的第一栈帧丢弃掉,相当于重新开始当前调试的方法。使用方法也算简单,在要丢弃的栈帧上右击,选择 Drop Frame 即可。或者直接单击调试窗口的 Drop Frame 按钮。不过需要注意的是,如果对象在子方法运行时发生了变化,是不会再变回去的。
官方文档传送门: https://www.jetbrains.com/help/idea/debugging-code.html#d181035e308
这是IDEA 2018年加入的新功能,可以直接在调试中抛出指定的异常。使用方法跟上面的弃栈帧类似,右击栈帧并选择 Throw Exception ,然后输入如下代码即可:
throw new NullPointerException()
官方文档传送门: https://www.jetbrains.com/help/idea/altering-the-program-s-execution-flow.html#throw_exception
这是IDEA2015版时增加的功能,类似上面的手动抛异常,只不过是返回一个指定值罢了。使用方法跟上面也都类似,右击栈帧并选择 Force Return ,然后输入要返回的值即可。如果是 void
的方法那就更简单了,连返回值都不用输。
官方文档传送门: https://www.jetbrains.com/help/idea/altering-the-program-s-execution-flow.html
利用Java虚拟机提供的HotSwap功能,我们可以做到一边调试一边改代码。只要在修改完代码之后,点击 Run -> Reload Changed Classes 即可。不过HotSwap有一些限制,例如不支持static的字段和方法等。
官方文档传送门: https://www.jetbrains.com/help/idea/altering-the-program-s-execution-flow.html#reload_classes
调试窗口里的 Settings -> Show Method Return Values 开关可以显示方法的返回值。例如以下方法:
private double random(){ return Math.random(); }
只要在 return
上设断点然后 Step Over ,或者在方法内部的任何地方设断点然后 Step Out 一下,便可以在调用处的变量窗口看到一个类似于这样的值: Test.random() = 0.28735657504865864
。在这个方法调用没有赋值给变量时(如 if (random() < 10)
)还挺有用的。
前面说了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
内存泄漏是一个比较头疼的问题,好在IDEA提供了内存分析工具,只要单击调试窗口右上角的 Restore ‘Memory’ View 就能看到内存窗口,然后点击其中的 Click to load the classes list 就能看到当前内存的对象分布情况。然后可以据此分析到底是哪个类的对象数量看起来有问题。
官方文档传送门: https://www.jetbrains.com/help/idea/analyze-objects-in-the-jvm-heap.html
如果只是想暂停一下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
功能熟悉了以后,熟练使用快捷键能够大幅提高效率。以下是笔者调试时经常使用的快捷键: