文章目录
  1. 1. 断点
    1. 1.1. 断点类型
    2. 1.2. 条件断点
    3. 1.3. 无断点暂停
  2. 2. 调试技巧
    1. 2.1. 智能进入(Smart step into)
    2. 2.2. 表达式评估(Evaluate expression)
    3. 2.3. 远程调试(Remote debug)
    4. 2.4. 弃栈帧(Drop frame)
    5. 2.5. 强制抛异常(Throw an exception):
    6. 2.6. 强制返回(Force return):
    7. 2.7. 自动载入变化代码(Reload changes)
    8. 2.8. 显示方法返回值(Show method return values)
    9. 2.9. 调试流(Trace Current Stream Chain)
    10. 2.10. 调试内存泄漏(Memory View)
    11. 2.11. 调试lombok
    12. 2.12. 其它
  3. 3. 快捷键

本文介绍了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方法,那么进入这个方法就相对麻烦一些。

1
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端口进行调试。

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

1
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开关可以显示方法的返回值。例如以下方法:

1
2
3
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:切换测试和实现
文章目录
  1. 1. 断点
    1. 1.1. 断点类型
    2. 1.2. 条件断点
    3. 1.3. 无断点暂停
  2. 2. 调试技巧
    1. 2.1. 智能进入(Smart step into)
    2. 2.2. 表达式评估(Evaluate expression)
    3. 2.3. 远程调试(Remote debug)
    4. 2.4. 弃栈帧(Drop frame)
    5. 2.5. 强制抛异常(Throw an exception):
    6. 2.6. 强制返回(Force return):
    7. 2.7. 自动载入变化代码(Reload changes)
    8. 2.8. 显示方法返回值(Show method return values)
    9. 2.9. 调试流(Trace Current Stream Chain)
    10. 2.10. 调试内存泄漏(Memory View)
    11. 2.11. 调试lombok
    12. 2.12. 其它
  3. 3. 快捷键