掌握这30个IDEA Debug 小技巧,开发、改Bug速度快10倍

 如遇图片加载失败,可尝试使用手机流量访问

大家好,我是一航!

写Bug、改Bug几乎占据了程序员日常工作的绝大部分时间,如果你能掌握一手调试代码的绝技,相信工作效率必定会得到大幅度的提升;

IDEA 就为我们提供了简单且非常强大的调试功能,但是很多小伙伴并没有真正的用上,今天就一起来玩一下那些Debug的奇淫巧计;30多个调试小技巧,学完后让你开发调试效率提升个10倍!争取做到早上9点上班,10点就能下班(小声说:是晚上10点【手动狗头】)

以下时本文的目录:

 如遇图片加载失败,可尝试使用手机流量访问

IDEA的Debug控制台在整个窗口的左下方;

 如遇图片加载失败,可尝试使用手机流量访问

IDEA 调试功能说明

  • Show Execution Point快捷键:Alt + F10回到当前激活的断点处;当你的鼠标不在断点所处的行,点击之后,会立马复位到断点处; 如遇图片加载失败,可尝试使用手机流量访问
  • Step Ove快捷键:F8单步调试;逐行往下执行,如果执行行有其他方法,不会进入对应的方法;日常Debug用的最多的一个功能 如遇图片加载失败,可尝试使用手机流量访问
  • Step Into快捷键:F7进入方法体内部。该功能会进入自定义的方法或者三方库的方法;注意,不会进入JDK的方法 如遇图片加载失败,可尝试使用手机流量访问
  • Force Step Into快捷键:Alt + Shift + F7强制进入方法体内部,与 Step Into不同的是,会进入JDK的方法; 如遇图片加载失败,可尝试使用手机流量访问
  • Step Out快捷键:Shift + F8跳出方法体;一般会配合 (Force)Step Into一起使用 如遇图片加载失败,可尝试使用手机流量访问
  • Drop frame回到方法的调用处,同时上下文内所有的变量的值也回到那个时候。该按钮能够点击的前提条件是:当前所处的方法有上级方法,如果你是main方法里,那么按钮就是灰色,无法点击; 如遇图片加载失败,可尝试使用手机流量访问 如遇图片加载失败,可尝试使用手机流量访问
  • Run to Cursor快捷键:Alt + F9将代码运行到光标处,光标停在哪里就运行到哪里; 如遇图片加载失败,可尝试使用手机流量访问
  • Evaluate Expression快捷键:Alt + F8表达式计算器;可执行任意合法的表达式。 如遇图片加载失败,可尝试使用手机流量访问 如遇图片加载失败,可尝试使用手机流量访问
  • Trace Current Stream Chain追踪当前Stream流;只有在Stream代码上,此按钮才会亮起。 如遇图片加载失败,可尝试使用手机流量访问
  • Rerun Main快捷键:Ctrl + F5查询执行Debug; 如遇图片加载失败,可尝试使用手机流量访问
  • Resume Program快捷键:F9恢复程序;当因为断点导致代码停止之后,此功能可以让持续恢复执行;有下一个断点时,会跳转到下一个断点;没有下一个断点,会执行到持续结束; 如遇图片加载失败,可尝试使用手机流量访问
  • Stop Main快捷键:Ctrl + F12停止程序; 如遇图片加载失败,可尝试使用手机流量访问
  • View Breakpoints快捷键:Ctrl + Shift + F8打开断点管理窗口; 如遇图片加载失败,可尝试使用手机流量访问
  • Mute Breakpoints停用所有的断点; 如遇图片加载失败,可尝试使用手机流量访问
  • Get Thread Dump拿到当前线程的Dump,可以查看当前线程的状态; 如遇图片加载失败,可尝试使用手机流量访问
  • 筛选 如遇图片加载失败,可尝试使用手机流量访问

调试小技巧

行断点

行断点的图标是一个 圆形的红点,在需要断点的代码行头点击,即可添加断点

 如遇图片加载失败,可尝试使用手机流量访问

方法断点

将断点打在某个具体的方法上,方法执行的时候,会进入断点;

举个方法调试最常用的Debug场景:

当阅读源码或者自己写业务需求的时候,经常会用到策略、模板方法等设计模式;在调试的时候,需要知道,当前接口方法或者抽象方法的执行,到底是走的哪一个具体的实现,用方法调试就能很方便的找到;如下示例;

 如遇图片加载失败,可尝试使用手机流量访问
 如遇图片加载失败,可尝试使用手机流量访问

接口 Service有两个具体的实现:ServiceA和 ServiceB,分别实现了接口的 method方法,调试的过程中就可以将断点打在接口的method方法上;当我们在Main方法中实例化了ServiceB,断点就自动进入到ServiceB的method()方法了;

  • 接口Servicepublic interface Service { void method(); }
    • ServiceApublic class ServiceA implements Service{ @Override public void method() { System.out.println("Service A"); } }
    • ServiceBpublic class ServiceB implements Service{ @Override public void method() { System.out.println("Service B"); } }
  • Mainpublic class Main { public static void main(String[] args) { Service serviceB = new ServiceB(); serviceB.method(); } }

更多功能点

 如遇图片加载失败,可尝试使用手机流量访问
  • Condition用于输入表达式,进行过滤
  • Watch
    • Emulated用于提高调试性能
    • Method entry进入方法时激活断点
    • Method exit退出方法时激活断点
    Method entry 和 Method exit 至少有一个选项存在。

属性断点

在属性的行头点击即可添加一个小眼睛一样的属性监听断点,用于监听某个属性的读写变化过程;

 如遇图片加载失败,可尝试使用手机流量访问

更多功能点

 如遇图片加载失败,可尝试使用手机流量访问
  • Condition用于输入表达式,进行过滤
  • Watch
    • Filed Access读取此属性时(写入时不管)
    • Filed modification写入此属性时(读取时不管)

异常断点

异常断点是开发、调试的时候经常用到的一个功能,用于快速定位到那行代码出现了异常;

 如遇图片加载失败,可尝试使用手机流量访问

设置方式:

  • 第一步,使用快捷键Ctrl + Shift + F8打开配置窗口;
  • 第二步,点击左上角的+号;
  • 第三步,选择Java Exception Breakpoints
  • 第四步,添加需要断点的异常,如:ArithmeticException
  • 第五步,Debug运行,当出现指定的异常时,就会进入断点;

更多功能点

 如遇图片加载失败,可尝试使用手机流量访问
  • Condition用于输入表达式,进行过滤
  • Watch
    • Caught excetion只有当你自己try-catch了这个异常才会激活断点
    • Uncaught excetion只有当你自己不try-catch时才会激活断点

临时断点

临时断点是指只触发一次的断点,之后就自动取消了;一般用于特定的场合下需要确认值是符合我们的预期,完了之后就不在需要了;

设置及演示过程如下:

2022010222100.gif 如遇图片加载失败,可尝试使用手机流量访问

设置方式:

  • 第一步,设置断点
  • 第二步,使用快捷键Ctrl + Shift + F8打开配置窗口;
  • 第三步,找到对应的断点;
  • 第四步,勾选Remove once hit
  • 第五步,Debug运行,当断点触发一次之后,就自动取消了;

断点条件

设置断点的触发条件,也是阅读源码、修复Bug经常用到的一个功能,比如读Spring源码,研究Bean生命周期的时候,就可以根据Bean的name去设置断点条件,用来判断之后在操作指定对象的时候,才进入断点;

如下示例:

  1. for循环之后只有i是2的倍数时,才进入断点,可以在Conditon中填入 i % 2 == 0
  2. 0-10000的循环,当i等于5000的时候,进入断点,其他的时候忽略,可以在Conditon中填入 i == 5000
 如遇图片加载失败,可尝试使用手机流量访问

设置过程:

  • 第一步,设置断点
  • 第二步,右键断点处,打开操作界面
  • 第三步,输入表达式,比如循环时只有偶数才断点,可以输入i % 2 == 0

模拟异常

开发过程中,有时候需要人为制造一些异常,比如事务操作(@Transactional),需要验证是否能达到回滚的效果;

比如下面的伪代码:

// 伪代码 假如这里是个事务操作
// @Transactional
public void save() throws RuntimeException{
    table1Save();
    // 我先在这里测试一下,异常之后,是否会滚
    //throw new RuntimeException("异常了");
    table2Save();
    table3Save();
}

void table1Save(){}
void table2Save(){}
void table3Save(){}

当咱希望在执行 table2Save()的时候,抛个异常,让整个操作回滚,通常的做法是会在代码中人为抛一个异常:

throw new RuntimeException("异常了");

这样做并没有什么错,但是不是很优雅,而且还存在一下的两个问题:

  • 只能在方法的末尾抛异常;流程中间抛,后面的代码会报错
  • 有风险这种业务功能中人为抛异常,如果一不小心忘记删除,将这个异常提交上去,就是人为的生产事故,可能带来比较严重的后果;

IDEA优雅模拟异常

那有没有什么更好的方式呢?IDEA给我们提供了更加优化的模拟异常方案,操作步骤如下:

 如遇图片加载失败,可尝试使用手机流量访问

操作步骤:

  • 第一步,在要模拟异常的地方加上断点;
  • 第二步,Debug模式运行代码并进入断点;
  • 第三步,Frames中找到对应的断点记录;
  • 第四步,右键,选择Throw Execption
  • 第五步,输入你想抛出的异常,点击ok,即可抛出对应的异常;

多线程调试

多线程开发的时候,线程的调度策略并不由代码控制,导致断点调试的过程可能会在线程间跳来跳去,如果逻辑复杂点,跳着跳着可能就蒙蔽了;如下示例:

public class Main {
    public static void main(String[] args) {
        System.out.println("0 main start");
        new Thread(() -> {
            System.out.println("1 hello");
        }, "thread1").start();

        new Thread(() -> {
            System.out.println("2 world");
        }, "thread2").start();

        System.out.println("3 main end");
    }
}

如果把断点打在 System.out.println上,除了0是能保证第一个输出的,1、2、3的执行顺序是没办法保证的;

默认情况下,断点的 suspend设置是 all,顺序并不固定;

 如遇图片加载失败,可尝试使用手机流量访问

如果将所有断点的 suspend设置为 Thread之后,就会按着线程的顺序,逐个去执行:

 如遇图片加载失败,可尝试使用手机流量访问

修改变量

在断点的过程中去修改某个变量的值;常见的场景是:当某个变量,以为逻辑bug导致其值和预期的不一样,但是又不想从头再进行debug,就可以直接在调试的过程中去修改变量的值,并继续执行后续的流程;

 如遇图片加载失败,可尝试使用手机流量访问

断点执行代码/方法/表达式

断点过程中,可以执行一段表达式、代码或者方法

  • 代码 如遇图片加载失败,可尝试使用手机流量访问
  • 方法执行 如遇图片加载失败,可尝试使用手机流量访问
  • 表达式 如遇图片加载失败,可尝试使用手机流量访问

远程调试

非常实用且特别装B的一个技能,当线上代码出现Bug之后,可以通过此方式进行远程调试,快速定位问题并修复;

注意:远程调试必须保证本地代码和线上代码版本一致,否则不会进入断点

设置步骤如下:

  • 添加一个用于远程调试的接口@RestController public class RemoteDebugController { @GetMapping("debug") public Integer debug(Integer p){ System.out.println(p); return p; } }
  • 将代码打成jar包mvn clean package -Dmaven.test.skip=true  如遇图片加载失败,可尝试使用手机流量访问
  • IDEA 设置远程配置 如遇图片加载失败,可尝试使用手机流量访问以下时几个重要参数的说明
    • Name名称,不重要,随意填写;
    • Host远端项目的IP,这里是本机测试,所以填写127.0.0.1即可,实际使用填写远端服务所在的IP地址
    • PORT远端调试的端口
    • 远端服务运行时的JVM参数IDEA 工具帮我们生成的服务运行时需要添加的JVM参数,直接复制使用即可;-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5555
  • 启动项目为了演示,这里就不在IDEA中启动了,直接在CMD窗口下启动测试项目java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5555 -jar spring-boot-001-hello-world-0.0.1-SNAPSHOT.jar  如遇图片加载失败,可尝试使用手机流量访问启动过程出现socket的监听日志,说明正常Listening for transport dt_socket at address: 5555
  • IDEA 远程调试配置 如遇图片加载失败,可尝试使用手机流量访问
  • 测试
    • 左侧为jar包运行的控制台
    • 右上方为IDEA的界面
    • 右下方为浏览器,模拟客户端请求;
    如下图示: 如遇图片加载失败,可尝试使用手机流量访问当客户端发起请求的时候,IDEA就会进入断点,当执行通过,可以看出,左侧控制台就会打印出对应的日志;线上调试,务必要给断点加上条件,比如特定测试账号才进去断点;避免让真是用户的请求也进入断点,影响用户的使用;通过此方式,如果远端的代码有bug,就可以直接在本地的IDEA工具中进行调试,非常的方便;

更多功能

上面列举了绝大部分常用的Debug功能,但是这并不是所有的,一些不常用功能可以根据需要选择使用

 如遇图片加载失败,可尝试使用手机流量访问

总结,工欲善其事必先利其器,利用好工具,就能做到事半功倍,赶紧收藏,用起来吧!

好了,今天的分享就到这里,感谢大家的点赞、转发、收藏!

作者:JackLee,如若转载,请注明出处:https://www.wlwlm.com/article/5546.html

JackLee的头像JackLee超级管理员
上一篇 2024年2月11日 下午12:39
下一篇 2024年2月11日

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注