因公众号更改推送规则,请点“在看”并加“星标”第一时间获取精彩技术分享
点击关注#互联网架构师公众号,领取架构师全套资料 都在这里
上一篇:2T架构师学习资料干货分享
大家好,我是互联网架构师!
工欲善其事,必先利其器
开发过程中,遇到运行结果和预期的不一致的时候,最有效的方法就是debug了。当然随着开发经验的增加,不通过debug直接看代码有时也能定位问题,但是十分依赖经验和运气,本地debug还是最直接和彻底的解决方式。开发的IDE从eclipse转到idea也好几年了,工作中积累了一些debug常用的方法,做个总结,后续有新的姿势了继续来补充。
debug
idea中,debug非常简单,找到你要断点的地方,鼠标左键点击就会出现一个红色小球,这就打上断点了,用debug方式启动程序后,触发你要debug的方法,就会帮你停在这一行。
debug的时候,有各种变量和表达式,有些可能在代码里面并不直接出现,但是对你debug挺重要,这里可以用这个表达式计算器来帮你验证各种表达式的值,不需要自己人工计算。点这个计算器的小图标,然后输入你的表达式,idea就会帮你计算出当前表达式的值。
条件断点
条件断点是debug中最常用的一个技巧,针对像for循环、递归等同一行代码在同一次触发中会反复进入的情况,如果没有条件断点,循环多少次就要在这个地方停多少次,十分麻烦,循环次数多了几乎在这个地方就无法断点。比例循环10000次,当前运行异常可以断定在6378次出了问题,如果不改代码,在循环中的某一行根本无法去打断点,打了之后就要手动放行6378次才能到,这时候只能通过修改代码,增加第6378次的判断,然后打再新增的代码上才能进去debug。有了条件之后,我们可以在断点上设置一个boolean表达式的条件,表达式为true的时候,才会在断点处停住。例如上面图片中的例子,i是0~4的循环,我们可以设置一个条件“i == 3”,这样只有在i == 3的时候,断点才会停住。设置条件断点的方法是,在断点上右键,弹出设置条件的面板,然后在条件中填入你的表达式,效果如下图
可以注意到,设置了条件断点后,断点icon的右下角会有一个小问号;运行起来后,并不是每次运行到这行代码都会停住,只有在满足i==3的时候,才会停住,这样我们就可以直接运行到出问题的那个循环。
单次断点
有些情况下,我们希望这个断点只生效1次就可以了,那我们就可以设置一下单次断点。设置的方法是先打开“Breakpoints”(左边侧栏2个红点的图标),找到你的断点,然后勾选上“Remove once hit”就好。
异常断点
这个也是开发中比较常用的一种断点方式。想象是否遇到过这样的场景:运行后报了空指针异常或者其他什么异常,但是当前堆栈信息不够判断是哪一行报的,比较传统的做法是,在方法开始的地方打一个断点,然后一步步跟着往下走,然后看看运行到哪一步会造成异常,如果方法比较长的话,这种方式比较费时。异常断点的意思是,并不直接在某一行设置断点,而是在某一种异常上设置断点,方法运行后,idea会帮你停在造成异常的这一行,这样的话,debug起来效率就高多了。设置异常断点的方法是,先打开“Breakpoints”,点击左上角的“+”,选择到“Java Exception Breakpoints”,然后所搜你想断点的异常,如果是自定义异常,可以选择到“Project”。
设置完成后,并不会在某一行出现断点的标志,因为运行之前idea也不知道哪一行会抛出这个异常,我们人造了一个空指针异常来验证,如下图所示
我们用debug启动后,idea帮我们停在了“s.length()”这里,这里s是空,所以会抛出空指针异常,这样我们就能通过异常断点的方式,直接让idea帮我们定位到了抛出异常的行。
强制返回
想象是否遇到过这样的场景:一个方法debug到底10行,我们已经知道问题了,这时候我们可能不想执行后面的代码了,因为后面的代码可能有写数据库、有远程调用、有发送消息,如果走了后面的代码我们后续要再恢复起来会比较麻烦,这时候我们最常见的操作是直接stop,但是很遗憾,直接stop后,后面的代码还是会被执行到,如下图所示,“这句在for循环之后执行”这句话在debug结束后还是会被打印出来。
那有没有办法让后续的代码不被执行呢?这里就可以使用强制返回。在Debug时找到Frames模块,里面找到当前正在debug的方法,右键,选择“Force Return”,这样就可以强制返回了,后面的代码不会被执行到。
如下图效果,就没有打印出“这句在for循环之后执行”,证明后面的代码缺失没有被执行
PS:有些同学的idea可能默认没有打开frames模块,可以在右边这个小魔方这里选择打开
抛出异常
有些时候,我们在调用方法的地方加了trycatch,或者用AOP的方式增加了统一的异常捕获,但是某一次在catch模块中处理结果和我们预期不一致,但是我们自己有的测试数据都不会发生异常,那我们就很难debug到catch模块的代码了。这时候我们可以在方法执行的过程中强制抛出某种异常,这样就可以保证debug到异常捕获的代码。设置的方法跟强制返回类似,选择抛出异常并且在表达式中创建想要抛出的异常即可:
如上图所示,在method1种强制抛出了空指针异常,我们在main方法的catch中就捕捉到了这个异常,这样就可以继续debug捕捉到异常后的处理逻辑,如下图所示
Drop Frame
在debug过程中,有时候在一步步往下走的时候,F8按快了多走了一步,导致关键的一行没有被停止到,这时候我们只能重来一次,如果遇到不太容易触发的分支,重来一次的代价是比较大的,有没有办法回溯呢?当然并没有完整的上一步的功能,但是使用drop frame,可以让某个子方法重新走一遍,一定程度上起到了上一步的作用。例如当前在method1种,走到了第2行,但是第1行是我们的关键行,我们可以drop掉method1这个方法的frame,这样就会回到调用method1的地方,可以再进入一遍。
第一次,过了method1的第1行,当前在第2行,选择method1这里的Drop Frame
这时候回退到调用menthod1的地方
可以按F7重新进入method1内部
执行结果后,可以看到method1的第1行的sout确实被执行了2次
好了,就先整理这些吧。如果你也有新的 debug 姿势,欢迎留言区里补充与评论。
· END ·
最后,关注公众号互联网架构师,在后台回复:2T,可以获取我整理的 Java 系列面试题和答案,非常齐全。
如果这篇文章对您有所帮助,或者有所启发的话,帮忙扫描上方二维码关注一下,您的支持是我坚持写作最大的动力。
求一键三连点赞、转发、在看