目录
视频来源:尚硅谷_宋红康_IDEA2022版本的安装与使用
【【尚硅谷】IDEA2022全新版教程,兼容JDK17(快速上手Java开发利器)】
https://www.bilibili.com/video/BV1CK411d7aA?p=16&vd_source=581d732b20cb23e01428068f153a99ed
编好的程序在执行过程中如果出现错误,该如何查找或定位错误呢?简单的代码直接就可以看出来,但 如果代码比较复杂,就需要借助程序调试来查找错误了。
运行编写好的程序时,可能出现的几种情况:
> 情况1:没有任何bug,程序执行正确!
======如果出现如下的三种情况,都又必要使用debug=======
> 情况2:运行以后,出现了错误或异常信息。但是通过日志文件或控制台,显示了异常信息的位置。
> 情况3:运行以后,得到了结果,但是结果不是我们想要的。
> 情况4:运行以后,得到了结果,结果大概率是我们想要的。但是多次运行的话,可能会出现不是我们想要的情况。 比如:多线程情况下,处理线程安全问题。
Debug(调试)程序步骤如下:
1、添加断点
2、启动调试
3、单步执行
4、观察变量和执行流程,找到并解决问
- package com.atguigu.debug;
-
- /**
- * ClassName: Debug01
- * Package: com.atguigu.debug
- * Description: 演示1:行断点 & 测试debug各个常见操作按钮
- */
- public class Debug01 {
- public static void main(String[] args) {
- //1.
- int m = 10;
- int n = 20;
- System.out.println("m = " + m + ",n = " + n);
- swap(m, n);
- System.out.println("m = " + m + ",n = " + n);
- }
-
- public static void swap(int m,int n){
- int temp = m;
- m = n;
- n = temp;
- }
-
- }
没有打断点之前 正常运行后 结果如下
这时候我们发现一个问题 执行结果没有替换过来 并不是我们想要的结果
在源代码文件中,在想要设置断点的代码行的前面的标记行处,单击鼠标左键就可以设置断点,在相同 位置再次单击即可取消断点。
这时我们打上断点
执行断点
这时我们的代码就会停留到第一个打断点的位置,也就是说我们用debug运行之后 代码会直接运行到我们第一个打断点的位置
这时我们当前的变量有形参args 值为空 m=10
这时我们会发现n=10并没有展示出来 那是因为我们在 int n=10 上面打了断点 是走到这个断点的位置 但是实际上这行代码并没有执行 也就是 int n=10 没有执行 换句话说 打断点的位置 实际上是没有执行的
或
接下来 我们学习一下F8
F8 : 进入下一步,如果当前行断点是调用一个方法,则不进入当前方法体内
比如 我们现在点击F8
在下一步
我们可以通过Console来看到他的输出语句
在下一步
在下一步
在下一步 程序结束
现在我们学习
F7: 进入下一步,如果当前行断点是调用一个自定义方法,则进入该方法体内
我们接着上面重新打上断点
F8 下一步
F8 下一步
到这里面 我们来研究一下swap(m, n);方法内部的运行情况
接下来 我们点击F7
这时我们可以看到我们已经进入到方面里面了
从栈也可以看到 原来我们在main线程里面 现在到swap方法里面
现在在这个方法 就是把前面 m=10 n=20 传进来了给了swap方法里面的二个变量swap(int m,int n)
接下来在 F8 temp = m;
int temp = m; 把m=10的值给了temp temp=10
下一步 F8 m = n;
下一步 F8 执行n = temp;
这个时候 我们发现 m和n 好像已经完成交换了 实际我们在认真查看 会发现 这个时候的m 和 n 是 swap(int m,int n) 方法里面的m 和 n
然后 我们观察一下 main方法里面的m和n 并没有发生变化
由上面的分析我们已经已经知道方法swap(int m,int n) 里面的执行情况 接下来 我们可以直接跳出这个方法 执行Shift+F8 跳出当前方法体
接下来 我们学习Shift+F8 跳出当前方法体
现在栈里面就只有一个main方法 main方法 里面的m和n还是10和20 m = 10 n = 20
拉下来 我们点击 结束程序
接下来
我们重新运行 打bug
如果我们想要从一个断点跳转到下一个断点的位置 就可以点击F9
F9: 恢复程序运行,但如果该断点下面代码还有断点则停在下一个断点上
在点击一下 F9 如果下面还有断点就达到下一个断点位置 如果下面没有断点 刚就退出程序
目前我们的案例 没有下一个断点 所以程序直接结束
接下来
我们重新在运行Debug
接下来 我们点击F8 下一步
如果这个时候我们想要查看println()方法里面的源码 这个时候我们点击F7 已经不好使了,如果我们点击一下 F7 会变成下面这个样子
所以我们 现在 重新运行debug
下一步F8
现在我要想进入println() 我们按Alt+Shift+F7
接下来点击Shift+F8 退出
接下来点击Shift+F8 退出
接下来点击Shift+F8 退出
接下来点击Shift+F8 退出
接下来点击Shift+F8 退出
接下来 我们在按Alt+Shift+F7
这样我们就可以进入到println()方法里面
进入到方法里面 如果想观察 可以F8 往下走
现在我们退出这个方法 Shift+F8 退出方法
退出来之后就到swap(m, n);
swap(m, n);方法是自己定义的方法 用F7可以进去 用Alt+Shift+F7 也可以进去
现在我们用Alt+Shift+F7 进入到swap(m, n);方法里面
接下来 我们学习
Run to Cursor(Alt + F9):直接跳到光标处继续调试
我们光标在2 就直接从1跳转到2进行调试
接下来 我们执行Shift+F8 跳出swap(m, n);方法
如果在执行的过程 不想让代码接着执行 可以点击Ctrl+F2 强制停止执行
Stop(Ctrl + F2):结束调试
接下来 学习 View Breakpoints(Ctrl + Shift + F8):查看所有断点
接下来 我们重新 执行一下Debug
接下来 学习一下ALt+F10
显示当前断点所在的位置 就比如我们查看到其他位置的时候 找不到断点 在哪里 可以按这个按钮 查看当前断点所在的位置
比如我现在光标在36行 不知道断点在哪里
现在我们点击ALt+F10 就可以看到当前断点在16行
接下来 我们打开 打开//2
点击运行
发现一个打印的是地址值 一个打印的是abc
现在我们用Debug来看下 运行情况
因为上面的断点都调试过 所以我可以直接F9 跳转到下一个断点
Resume Program(F9):恢复程序运行,但如果该断点下面代码还有断点则停在下一个断点上
为会么这里面打印的是一个地址值呢?
这时我们点击Alt+Shift+F7
Force Step Into(Alt +Shift + F7):进入下一步,如果当前行断点是调用一个核心类库方法,则进 入该方法体内
这时我们就进入到println()方法里面
在这个方法里面 此时他调用的是Object x 方法
Object x 方法默认可以打印对象的地址String s = String.valueOf(x);
现在我们点击Shift+F8 跳出println()方法
Step Out(Shift + F8):跳出当前方法体
跳出来之后 到这里
接下来 点击 F9 跳转到下一个断点的位置
Resume Program(F9):恢复程序运行,但如果该断点下面代码还有断点则停在下一个断点上
然后我们在点击Alt +Shift + F7 进入到println()方法
Force Step Into(Alt +Shift + F7):进入下一步,如果当前行断点是调用一个核心类库方法,则进 入该方法体内
这个时候他调用的方法char[] x 是对数组进行遍历的一个操作 所以输出的是abc
然后 在按Shift + F8
Step Out(Shift + F8):跳出当前方法体
接下来 按住F9 结束程序
Resume Program(F9):恢复程序运行,但如果该断点下面代码还有断点则停在下一个断点上
从Debug后 我们就可以看出为什么输出的结果 不一样呢 主要是因为 他们调用的方法不同
断点设置在方法的签名上,默认当进入时,断点可以被唤醒。
也可以设置在方法退出时,断点也被唤醒
如果断点是打上执行语句上是一个圆的 如果是打在方法的签名 是一个菱形
然后 我们在Debug
接下去F8
F9
在重新Debug
F9
F9
接下来 打开 //2.类的多态性 //3.接口的多态性
在Debug 这时候我们会发现 我们明明没有在Son 里面点击 可是他也停留了
这是因为代码的重写 也是覆盖行为 Son里面的test()对Father里面的test()是一个覆盖行为
所以我们断点打在父类Father上 被唤醒 后 子类Son也被唤醒
所以断点就停留在子类上 所以我们实际执行的是子类重写父类的一个方法
F9
F9
打开//4.
现在我们来看一下 resize() 被调用时的执行情况
put调用putVal putVal调用resize
在Debug
这个是让断点都不起作用 看起来好像有 实际上是没有的
在类的属性声明上打断点,默认对属性的修改操作进行监控
Debug
发现Debug 不起作用 是因为前面关闭了Debug 我们重新打开就可以了
如果到这个界面 是因为 我前面在Debug02.java 有打了断点 记得把它取消就可以
在重新Debug
F9
F9
F8
F9
Debug
3次F9
F9
Debug
如果满足条件 刚停留
F9
F 9
F9
F9
也就是说只要满足arr[i] %3 == 0 就停留
对异常进行跟踪。如果程序出现指定异常,程序就会执行断点,自动停住。
记得把以下代码开起来
- int m = 10;
- int n = 0;
- int result = m / n;
- System.out.println(result);
Debug
F9
接下来 把以下代码注释掉
- /* int m = 10;
- int n = 0;
- int result = m / n;
- System.out.println(result);*/
把以下代码打开
- Person p1 = new Person(1001);
- System.out.println(p1.getName().toUpperCase());
Debug
F9
"Thread2".equals(Thread.currentThread().getName())
F9
F9
页面把前端数据发到java后台 java后台把数据保存到数据库中 在这个过程中进行调试
Debug
F7 进入到insert()方法内
F8
当执行到这行的时候 发现了问题 这个时候下一步就是写入数据库 而我们现在不想让他加入
这个时候 我们就可以执行以下操作
F9
学习一下 HashMap底层的执行过程
Debug
Alt+Shift+F7 进入到put 方法
这个时候跳转到自动装箱去了 我们Shift+F8 跳出
在Alt+Shift+F7进入
在 Shift+F8 跳出
F8
F8
Ctrl+F2
问题:使用Step Into时,会出现无法进入源码的情况。如何解决?
方案1:使用 force step into 即可
方案2:点击Setting -> Build,Execution,Deployment -> Debugger -> Stepping
把Do not step into the classess中的 java.* 、 javax.* 取消勾选即可。
经验:初学者对于在哪里加断点,缺乏经验,这也是调试程序最麻烦的地方,需要一定的经验。 简单来说,在可能发生错误的代码的前面加断点。如果不会判断,就在程序执行的起点处加断点。