Debug调试技巧

这里以IDEA默认Debug快捷键为例(其实不同编辑器大同小异),功能上基本上都支持:

F7——step into  进入方法内部

F8——step over 逐行执行,但若当前行有调用了子方法,则不进入,step over过去

shift +F8——step out  出来,即step into的反向操作

F9 —— 跳至下一个断点处

 

除了字面意义以外(短一些的代码这些功能已经够用了,大不了一直F7),要注意一些细节:

1) F7——step into  进入方法内部,但是一般只会进入Java语言层面的方法内部,如System.out.println("Hello world");并不会下到println()方法内部。不知道这个判断是否下沉的标准是什么,暂且认为是.java还是.class。

如果真的想要追踪代码进入没有进入的方法的内部,可以使用shift+F8 (Smart step into),或者alt+shift+F8 (smart step into)。

2) F8——step over 逐行执行,但是确切地说是:当前层级下,下一行要执行的代码,咋一看上去好像没有什么区别,但是例如

①  F8时并不会下沉到 System.out.println("Hello"),因为step over是相对于当前行(断点所在的行)的层级去step over,对于上例,和for循环平级的下一行是 System.out.println("Bye")。

②  但是,F8也不会直接到System.out.println("Bye"); 因为F8——step over 确切地说是“当前层级下,下一行要执行的代码”。可以看到,和i为0时同一层级下的“下一行代码”是i为1,后面还有2。故要按F8次才能到System.out.println("Bye")。

这里的“下一行”和Java字面上的下一行代码并不完全相等,是逻辑上的要执行的下一行代码,同样的,step over也不是仅仅是字面上物理的over,而是逻辑上的。

也就是说,在遇到循环(for while do)时,F8不会直接跳过,会在for那一行停留循环次数(不会进入循环体),但是对于一些很大的循环,或者完全不想观察当前循环的情况了,可以在目标去除当前断点,或者在目标行(如本题的System.out.println("Bye"))设置一个新断点,F9——下一个断点直接跳过去。

这一点在step over是遇到了方法,而方法内部是有断点的,但我们只想看当前层级的结果,并不像下沉,e.g.

setFlag(row, j)行有个断点,而setFlag()方法定义中也有断点(调试setFlag用的),并且solveNQueen_impl()和clearFlag()方法内部都有断点。但此时只想知道这三个方法顺序执行的结果对不对(这在定位bug中很常见,从外到里,先确定外层是哪一步结果不对,定位以后再进去看),该怎么办呢?

可以把除了当前断点的全部断点移除,然后Step over调试当前的,之后恢复。

           ③ step over 并不能over掉断点,①中讲到,step over能跨越循环体内部(不会执行System.out.println("Hello")),但是这也不是绝对的,如果循环体中有断点,则会也必然会进入的,e.g.

下一次循环即i为1时,在去往i为2途中,还是step over不掉这一行。

也就是说,step over是over当前层级,不会下沉,但是over不掉下面层级的断点。此时的F8——step over有点像F9——下一个断点。但是二者又有一点不同,可以模拟一下,当进入了System.out.println("Hello"),此时继续F8,此时的“基”的已经变了,此时的F8是对当前这个断点的F8,故还会去执行System.out.println("World")。然后继续F8,此时会遇上for循环的断点,跳不过去,F8的“基”又变成了for循环,继续i为1...

 

 

3)shift +F8——step out 出来,即和F7反向。

4)F9 —— 跳至下一个断点处

和step over 一样,F9到下一个段点的也是逻辑上的下一个段点,并且是不分层级的下一断点,如:

在for上的断点F9则直接进入到System.out.println("Hello"),再F9则回到for,F9再下去,循环三次。但是注意,并不会执行System.out.println("World"),说白了,F9是到执行路径上的下一个断点,而且仅仅是断点本身。