⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 juejin.cn/post/7308539123537592357 「FirstMrRight」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言都将得到认真回复。甚至不知道如何读源码也可以请教噢。
  4. 新的源码解析文章实时收到通知。每周更新一篇左右。
  5. 认真的源码交流微信群。

目录

引言

IntelliJ IDEA,由JetBrains(捷克共和国)开发的一款强大的Java集成开发环境(IDE),因其丰富的功能、智能的代码辅助以及用户友好的界面设计,在全球范围内广受Java开发者的喜爱,在国内,笔者遇到过不使用IDEA的Java程序员不超过三个。不仅限于Java,IntelliJ IDEA还支持多种其他编程语言和框架,如Kotlin、Scala、Groovy以及Android开发等,这进一步扩大了其用户基础。其社区版是免费的,而专业版则提供了更为高级的功能。

Debug(调试)是软件开发中不可或缺的一个环节。它使开发者能够逐行执行代码,检查运行时的状态,包括变量值、内存占用、线程状态等,从而帮助开发者理解代码的实际行为,定位并修复错误。良好的调试工具可以显著提高问题解决的效率,减少猜测工作,帮助开发者构建更加稳定、高效的软件系统。


在本文中,我将向大家介绍及演示IDEA的高阶Debug技巧,包含但不限于:

  • 条件断点(Conditional breakpoint): 允许开发者设置特定条件,只有当这些条件满足时,程序才会在这些断点处暂停执行。这对于调试复杂的循环和分支逻辑尤其有用,因为它可以让你聚焦于特定的执行路径或案例。
  • 计算器(Evaluate Expression): 这个功能允许开发者在调试会话中计算表达式的值,不仅可以查看变量的当前值,还可以执行表达式,甚至调用方法。这对于验证假设和测试代码更改而无需重新启动整个调试会话非常有用。

Debug基础

写一段代码,开启调试:

操作 Windows Mac(OS X)
进入下一步,如果当前行断点是一个方法,则不进入当前方法体内 F8 F8(Fn)
进入下一步,如果当前行断点是一个方法,则进入当前方法体内, 如果该方法体还有方法,则不会进入该内嵌的方法中 F7 F7(Fn)
智能步入,断点所在行上有多个方法调用,会弹出进入哪个方法 Shift + F7 ⇧F7 (Fn)
智能跳出 Shift + F8 ⇧F8 (Fn)
恢复程序运行,如果该断点下面代码还有断点则停在下一个断点上 F9 F9(Fn)
运行到光标处,如果光标前有其他断点会进入到该断点 Alt + F9 ⌥F9(Fn)
计算表达式(可以更改变量值使其生效) Alt + F8 ⌥F8 (Fn)
切换断点(若光标当前行有断点则取消断点,没有则加上断点) Ctrl + F8 ⌘F8 (Fn)
查看断点信息 Ctrl + Shift + F8 ⌘⇧F8 (Fn)

表格来源于:程序猿DD

高阶技巧-条件断点

我们构造一个List<User>用来模拟从数据库查询出列表,第三个元素id=3中的age属性是null,我们在for循环中使用加法来触发Integer类型的拆箱来出发空指针异常。

public class IDEATest {
public static void main(String[] args) {

List<User> userList = new ArrayList<>(6);
userList.add(new User(1, "Tom", 19));
userList.add(new User(2, "Giles", 25));
userList.add(new User(3, "Alex", null));
userList.add(new User(4, "Ryan", 21));
userList.add(new User(5, "DongGe", 19));
userList.add(new User(6, "RUI", 21));

userList.forEach(user -> {
String name = user.getName();
int futureAge = user.getAge() + 10;
System.out.println(name + " 10年后" + futureAge + "岁");
});
}

}

@Data
@AllArgsConstructor
@NoArgsConstructor
class User {
private Integer id;

private String name;

private Integer age;
}

可以看到IDEA提示了第25行代码报了错,我们定位到第25行代码内容:

为了定位问题,我们在第25行打个断点:

null + 10

在Java中,null是一个字面量,用来表示没有任何对象与之关联的引用。而+操作符在Java中主要有两种用途:一是作为数学加法运算符,用于基本数据类型的数值相加;二是作为字符串连接运算符,用于将两个字符串拼接在一起。

当你尝试执行null + 10这样的表达式时,Java会尝试找到一个合适的操作符重载来处理这个表达式。由于null不是一个数值,所以不能直接进行数学加法。但是,如果参与+操作的任一操作数是一个字符串,Java会将另一个操作数转换为字符串,并执行字符串连接操作。

条件断点应用场景

为了定位到具体哪一条数据出了问题,我们需要按F9或点击箭头处按钮直到循环到错误数据,案例中共6条数据,即使最后一条数据错误,我们也只需要按五次即可发现问题数据,但是在正式/测试环境中,你无法确认从数据库中查询到多少条数据,假如是1000条,接下来很长一段时间你将被这个问题所困扰。显然我们应该拒绝这种没有效率、无意义、重复性的工作。

如何添加条件断点

鼠标移至红色断点处,使用右键:

在Condition中添加判断条件,上文中出现的异常是NullPointerException,我们就判断循环中的user对象age变量为null的即可:

Objects.isNull(user.getAge())

点击Done,确认。

重启Debug,我们可以看到循环出的第一条数据不再是列表的第一条,而是问题数据:

这样我们便可以很快的定位到错误数据,解决问题。

条件断点对于阅读源码的帮助

例如,我们在阅读Spring Framework源码时,条件断点可以帮助我们快速定位到正在目标Bean。

Spring Boot项目在启动时,会加载所有被标注的元数据,此时我们自定义了一个Bean的类型叫a,我们可以在BeanFactoryUtils对应的加载方法中添加条件断点,这样就可以更快的查看我们自定义的Bean的加载逻辑。

高阶技巧-计算器

在2023新版IDEA中,可以通过以下步骤找到计算器,或者通过快捷键的方式找到计算器。

查看变量值

在断点暂停时,你可以使用计算器来查看和评估变量的当前值,这比在变量监视窗口中查找要快得多。

修改变量值

修改变量值:如果你想要测试代码对于不同变量值的反应,可以使用计算器改变变量的值,而无需修改代码并重新启动调试过程。

测试表达式

如果你在编写代码时不确定某个表达式的结果,可以使用计算器快速进行测试,而不必写额外的测试代码或者等待代码运行到那一点。

执行方法调用:

通过计算器,你可以在不影响当前程序执行状态的情况下执行方法,这样可以帮助你理解方法的行为或者验证方法的返回值。

文章目录
  1. 1. 目录
  2. 2. 引言
  3. 3. Debug基础
  4. 4. 高阶技巧-条件断点
    1. 4.1. 条件断点应用场景
    2. 4.2. 如何添加条件断点
    3. 4.3. 条件断点对于阅读源码的帮助
  5. 5. 高阶技巧-计算器
    1. 5.1. 查看变量值
    2. 5.2. 修改变量值
    3. 5.3. 测试表达式
    4. 5.4. 执行方法调用: