3 程序调试
3.1 为什么需要程序调试
问题:张浩代表学校参加航模比赛。收到航模后,他迫不及待地组装起来,组装完成后发现有几个零件没使用到。后来他对照说明书发现其中一步出错了,最后解决了问题。解决问题后,张浩想到在编写程序过程中有时也会出现错误,那么有没有好的方法发现和定位错误呢?
分析:或许大家都经历过通过代码阅读或者添加输出语句查找程序错误的阶段。当程序结构越来越复杂时,这样的做法不能满足需要。当程序存在错误的时候,我们需要专门的技术来发现和定位错误,这个技术就是“程序调试”。
3.2 什么是程序调试
"调试" 这个词在生活中也经常听到,如电器调试、仪表调试。生活中的调试一般是指初装电器或电器出现问题时排除故障的过程,首先发现问题所在,然后调整电器的某些设置,最后使其达到正常的运行状态。在程序设计领域,调试的概念与其类似,但又有不同。
为了找出程序中的问题所在,希望程序在需要的地方暂停,以便查看运行到这里时变量的值。还希望单步运行程序,跟踪程序的运行流程,观察哪条语句执行了,哪条语句没有执行。
满足暂停程序、观察变量和逐条执行语句等功能的工具和方法总称为程序调试。
问题:顺序输出1~5这五个数字。
示例6
package cn.jbit.loops1;
public class DebugDemo {
/*
* 程序调试演示代码
*/
public static void main(String[] args) {
int i = 1;
System.out.println("程序调试演示,注意观察i的值:");
while(i < 5){
System.out.println(i);
i++;
}
}
}
运行示例6的代码,只输出了四个数字,如图5.7所示。程序中哪里出错了呢?
图5.7只输出了四个数字
如何定位错误呢?使用IDEA提供的调试功能解决这个问题,由以下两个步骤完成。
(1)分析错误,设置断点。
断点用来调试的时候确定程序停在某一行代码处,以便发现程序错误。
设置断点的方法很简单,在想设置断点的代码行左侧边栏处双击,就出现一个圆形的断点标记圖,再次双击,断点即可取消。
当程序发生错误时,分析错误的位置,在该位置设置断点,程序运行到断点处就会停下来,即可在IDEA的变量视图中看到变量的值,然后通过单步执行,一步步运行程序。
(2)启动调试,单步执行。
设置好断点后,就可以单击"启动调试"按钮|,即可开始调试,如图5.8所示。
图5.8启动调试
启动调试后,IDEA会提示或自动转到调试视图,并在断点处停下来,这时可以在调试视图中单击按钮或按F8键逐条执行语句(又称单步执行),如图5.9所示。
图5.9单步执行
调试中,代码运行到哪一行,左侧边栏就会有一个粉色的背景指示,同时该行代码的背景色变成深蓝色,如图5.10所示。
图5.10当前代码行
回到前面的问题,单步执行程序,发现当i值等于5时就退出了循环。循环只运行了四次,所以只输出了四个数字,如图5.12所示。
图5.12发现问题
知道了问题所在就可以很容易地解决问题了,修改循环条件为i<=5,再次运行程序,即可输出五个数字。
小知识:计算机程序中的错误或缺陷通常称为“bug”,程序调试称为“debug”,就是发现并解决bug的意思,如图5.13所示。
“bug” 这个单词本身是“虫子”的意思,将计算机程序中的错误或缺陷称为bug是有原因的。在电子管计算机的年代,一台计算机的主机重达数吨,常常占据整个房间。在某个实验室的某个早晨,这台计算机突然停止了工作,我们的IT前辈马上开始寻找出现这种情况的原因。凭借设计图样的引导,他们很快就圈定了可能发生问题的位置。在后来的检查中,他们发现原来是一只虫子在爬过两只继电器时造成了短路。在修复了计算机并重新开始工作之后,负责计算机维护的工程师把这次故障记录在一份备忘录上,以便将来其他人遇到类似的情况时可以迅速地找到答案。他还写了一份文档给计算机的设计人员,希望以后在主机的散热孔处加装一层更加细密的金属网,既不影响散热,又可以防止虫子爬到主机里。
因此,人们把计算机系统中的缺陷称为bug,这个名词一直从计算机硬件故障沿用到了计算机软件故障。
大家在以后的编程过程中,一定要仔细认真。如果出现了 bug且不好确定它的位置,可使用程序调试,通过设置断点并单步执行,找到问题所在,最后修改程序。
4 for循环
4.1 为什么需要for循环
通过使用while循环,张浩轻松解决了老师补充的问题,连续输出100次 "好好学习,天天向上!",如示例1所示。
示例 1
public class Main {
public static void main(String[] args) {
int i = 0;
while(i < 100) {
System.out.println("好好学习,天天向上!");
i++;
}
}
}
观察代码不难发现,这里的循环次数 "100" 已经固定,对于这种情况我们也可以选用for循环结构来实现,如示例2所示。
示例2
public class Main {
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
System.out.println("好好学习,天天向上!");
}
}
}
通过运行程序,我们可以看到示例1和示例2的输出结果是一样的,但示例2的代码看起来更加简洁。因此,在解决有固定循环次数的问题时,可以首选for循环结构。下面就来介绍for循环结构。