当程序员写完一个代码时必然要运行这个代码,但是一个没有异常的代码却未必满足我们的要求,因此就要求程序员对已经写好的代码进行调试操作。在之前,如果我们要看某一个程序是否满足我们的需求,一般情况下会对程序运行的结果进行打印,用以观察程序执行的结果是否满足设计需求。这种方法有两个很明显的弊端,一个是频繁对程序中的数据进行打印不仅增加了代码的冗杂程度,而且如果没有对打印的数据进行注释,那么就很难对不同的数据进行区分;其次,如果运行的结果并不符合设计需求,那么就需要我们按照程序运行的流程走遍整个程序,以此检查不符合需求的部分,倘若这个不满足需求的部分出现在循环结构中,那么这个工作量无疑是巨大的,单靠人脑跑遍整个循环结构明显不现实。为了处理这样的问题,在开发环境中提供了分析程序的手段——断点breakpoint。
在IDEA中,我们通过在代码的左侧的行号后面单击左键添加断点,断点添加成功后会在行号后面出现一个红色的圆点,再次单击左键可以取消断点。在定义了断点之后,右键在弹出的窗口中选择Debug按钮或者单击右上角的虫子模样的按钮就可以对程序进行调试操作,程序会在定了断点的地方停下来,并显示出此时涉及的变量以及常量的当前值,如下图所示:
当我们点击Debug按钮对程序进行调试以后,在IDEA界面上会跳出一个下图模样的窗口,这个窗口可以简单的分为三大块,分别是方法栈的浏览区域,操作区域一击变量值的观察区域。在方法栈的浏览区域中包括了线程以及在我们定义了断点时正在执行没有退出栈帧的方法,最上面一行表示线程,下面表示的是方法的栈帧,方法名后面的数字表明了程序执行的行号;在变量观察区注意到有一个this,this的后面跟了一个类的名称,点开这个this能后看到这个类中储存的常量以及变量的相关信息;左侧的操作区是对程序的执行或停止等进行操作,上侧的操作按钮涉及到的是程序调试的相关内容,分别代表了step over、step into、force step into、step out、run to cursor。
第一个图标step over是单步调试,表示跳过该方法,即如果当前执行的是一个方法,那么会把这个方法当作一步执行完,不会进入这个方法的内部。第二个图标step into也是单步执行,表示进入自定义方法,即如果当前执行的是一个自定义方法,那么在按下这个按钮后吗,程序会进入这个自定义方法的内部,不过不会进入JDK内部的方法。比如我们对第一张图片中的程序进行修改,添加一个自定义方法go,并对其进行调用,仍然在第7行添加断点。程序如下所示:
package com.duandian.demo;public class DuanDianDemo {private int num = 10;public void run(int a ){num = a*num;System.out.println(num);go(num);}public void go(int b){System.out.println("DuanDianDemo.go");System.out.println("num="+b);}public static void main(String[] args) {DuanDianDemo duanDianDemo = new DuanDianDemo();duanDianDemo.run(3);}
}
这时,如果我们点按step over图标,则会发现,当代码执行到go(num);这一行时,代码会将它当作一行普通代码执行,并不会进入方法内部,但如果我们点击的时step into按钮,那么程序执行到这一行时则会进入go方法的内部,如下图所示(注意区分执行完go(num)这行后光标所在的行的位置)。
第三个图标是force step into,它表示的是强制进入方法内部,因此在按下这个按钮的时候,程序可以进入任何方法,包括JDK的内部方法。第四个图标是step out,表示跳出方法,当我们用单步调试对程序进行调试并且进入子方法内部时,如果按下step out 按钮,那么程序会自动执行完子方法剩余的部分,并且跳出子方法,即使是进入JDK内部的方法,也能通过这个操作进行退出。
最后一个图标是 run to cursor,它表示一直执行直到光标停止,如果用在普通程序中,一般就是将整个程序执行完成,而在循环结构中,点击依次就代表循环一次,比如我们在上上面的程序中添加循环结构,代码变为下面样子,这时先用单步调试让程序进入循环结构,然后按下run to cursor图标,调试结果如下面的三组图片所示,要注意对比图中数据的变化:
package com.duandian.demo;public class DuanDianDemo {private int num = 10;public void run(int a ){num = a*num;System.out.println(num);go(num);}public void go(int b){System.out.println("DuanDianDemo.go");System.out.println("num="+b);}public static void main(String[] args) {DuanDianDemo duanDianDemo = new DuanDianDemo();duanDianDemo.run(3);for (int i = 0; i < 3; i++) {System.out.println(i);}}
}