挖掘IntelliJ IDEA的调试功能

本文介绍了 IntelliJ IDEA 的一些相对不那么广为人知,但是又很实用的调试功能。希望能让你的IDE发挥出最大的功效!本文使用的IDEA版本是 2018.1 社区版,快捷键是 Mac OS X 。本文的兄弟篇是 挖掘IntelliJ IDEA的实用功能

断点

断点类型

一般来说调试时,我们都是在代码行上鼠标一点,然后运行测试,遇断点所在的行即停,这就是所谓的行断点。IDEA支持以下几种断点类型:

  1. 行断点(Line Breakpoints):就是我们最经常用的方式。
  2. 方法断点(Method Breakpoints):如果你看到代码调用了一个接口,但不知道具体会跑在哪个实现上,便可以在接口上设置断点,这样不管哪个子类运行到这个方法都会停下来。
  3. 异常断点(Exception Breakpoints):可以在 Run -> View Breakpoints 中的 Java Exception Breakpoints 里添加异常的具体类型。这样的话,程序中一旦发生了这种异常马上就会停下来。
  4. 字段断点(Field Watchpoints):可以设置在字段上,这样读写字段都可以触发。需要注意的是,默认只有写才会停下,想要让读取时也停下,需要右击断点,在 WatchField access 上打勾才行。

条件断点

断点是可以设置条件的,这样便可以只在关心的时候停下来。比如说循环里处理一堆字符串,但是只关心特定的字符串,那条件断点便可以派上用场。按住Shift键设置断点,或是右击断点之后选择 More 来打开以下界面:

上图就是设置条件断点的界面,直接在 Condition 里输入条件即可,如 "ggg".equals(name) 。需要注意的是, Suspend 默认是没有打勾的,必须勾选上才能让程序暂停。另外,辛辛苦苦设置的特定断点,是可以拖拽到别的地方去的,这样就省的到处敲来敲去的了。还有一个小技巧是按住Alt的同时设置断点,可以让断点仅停一次便自动消失。在设置临时断点时有点用。

无断点暂停

如果在很长的循环时不知道程序运行到哪里了,可以在调试时点击调试窗口上的 Pause Program ,这样程序便能在当前执行的地方暂停。另外,运行到光标(Run to cursor)也可以在没有设置断点的时候让程序运行到光标所在行时暂停。

调试技巧

下面介绍一些调试的小技巧。

智能进入(Smart step into)

当调试程序运行到类似这样的句子时,如果你想看的是 actor.action 方法,那么进入这个方法就相对麻烦一些。

actor.action(actionProvider.provide(action.getName()));

这时可以使用调试窗口上的智能进入,程序会弹出一个对话框,我们选择需要的调用处即可。算是一个提升调试效率的小技巧。

官方文档传送门: 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 端口进行调试。

-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 ,然后调试它即可。

弃栈帧(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 ,然后输入如下代码即可:

throw new NullPointerException()

官方文档传送门: 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 开关可以显示方法的返回值。例如以下方法:

private double random(){
    return Math.random();
}

只要在 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 ,但它能够工作。

如果想设断点的是 toStringhashCode 等方法,可以在调试时使用: 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:切换测试和实现
我来评几句
登录后评论

已发表评论数()

相关站点

热门文章