问题:为了帮助张浩尽快提高成绩,老师给他安排了每天的学习任务:上午阅读教材,学习理论部分;下午上机编程,掌握代码部分。老师每天检查学习成果,如果不合格,则继续进行。
分析:对上面的问题,循环条件:老师没有给出满意的评价,就要继续执行任务。循环操作:上午阅读教材,下午上机编程。通过从控制台输入y或n表示老师的评价是“合格”或“不合格”,根据这个条件决定是否执行循环操作。根据while循环的语法,可以得到如示例5所示的代码。
示例5
package cn.jbit.loops1; import java.util.Scanner; public class WhileDemo3 { /* * 如何使用while循环 */ public static void main(String[] args) { String answer; //标识是否合格 Scanner input = new Scanner(System.in); System.out.print("合格了吗?(y/n):"); answer = input.next(); while(!"y".equals(answer)){ System.out.println("上午阅读教材!"); System.out.println("下午上机编程!\n"); System.out.print("合格了吗?(y/n):"); answer = input.next(); } System.out.println("完成学习任务!"); } }
分析代码,可能会有以下问题。上一章学到了从控制台获得输入时需使用Scanner,为什么这里语法有变化呢?这是因为以前学的是从控制台获得一个整数,而这里需要从控制台获得一个字符串,将其保存在String类型的变量answer中,代码如下:
answer = input.next();
如何判断输入的字符串是不是"y" ?
回顾上一章,比较两个int类型或char类型变量是否相等,我们使用运算符"==”。这里,answer是String类型的变量,判断String类型变量是否相等通常采用下面的方法。
//判断 String 型的变量 strl 是否等于 str2, 若相等,则值为 true, 若不相等,则值为 false String strl = "yes"; String str2 = “no"; boolean bool = strl.equals(str2); System.out.println(bool);
以上代码运行后将输出false。因此,"y" .equals(answer)用来判断变量answer的值是不是小写英文字母y。 !"y" .equals(answer)的含义:当answer的值不是y的时候,其值为true;answer的值是y的时候,其值为false。所以运行程序后输入y的时候,循环可以退出。程序运行结果如图5.6所示。
图5.6示例5的运行结果
通过示例5可以得到使用while循环结构解决问题的步骤。
说明:使用while循环结构解决问题的步骤如下。
(1) 分析循环条件和循环操作。
(2) 套用while语法写出代码。
(3) 检查循环能否退出。
注意:使用while循环结构解决问题时,一定要注意检查循环能否退出,即避免出现“死循环”现象。检查下面的代码。
package cn.jbit.loops1; public class ErrorDemo { public static void main(String[] args) { int i = 0; while(i < 4){ System.out.println("循环一直运行,不会退出!"); //这里缺少什么? } } }
分析代码,会发现在循环操作中一直没有改变i的值。i的值一直为0,即始终满足i<4的循环条件,因此循环会一直运行,不会退出。修改的方法是在输出语句之后增加语句:
i++ ;
永远不会退出的循环称为“死循环”。“死循环”是编程中应极力避免出现的情况,所以对于循环,编写完成后要仔细检查循环能否退出。
常见错误1
使用while循环结构解决问题时,经常会遇到下面的一些错误。
(1)没有为循环变量赋初值。
检查下面的代码。
package cn.jbit.loops1; public class ErrorDemo { public static void main(String[] args) { int i; while(i < 4){ System.out.println("循环"); i++; } } }
分析代码,会发现没有给循环变量i赋初值,程序编译将出现错误,并提示 “为变量i赋初值”。
(2)缺少{}。
运行下面的代码,将会出现什么结果?请动手尝试一下。
package cn.jbit.loops1; public class ErrorDemo { public static void main(String[] args) { int i = 0; while(i < 4){ System.out.println("循环"); i++; } } }
5.3 程序调试
5.3.1 为什么需要程序调试
问题:张浩代表学校参加航模比赛。收到航模后,他迫不及待地组装起来,组装完成后发现有几个零件没使用到。后来他对照说明书发现其中一步出错了,最后解决了问题。解决问题后,张浩想到在编写程序过程中有时也会出现错误,那么有没有好的方法发现和定位错误呢?
分析:或许大家都经历过通过代码阅读或者添加输出语句查找程序错误的阶段。当程序结构越来越复杂时,这样的做法不能满足需要。当程序存在错误的时候,我们需要专门的技术来发现和定位错误,这个技术就是“程序调试”。
5.3.2 什么是程序调试
"调试" 这个词在生活中也经常听到,如电器调试、仪表调试。生活中的调试一般是指初装电器或电器出现问题时排除故障的过程,首先发现问题所在,然后调整电器的某些设置,最后使其达到正常的运行状态。在程序设计领域,调试的概念与其类似,但又有不同。
为了找出程序中的问题所在,希望程序在需要的地方暂停,以便查看运行到这里时变量的值。还希望单步运行程序,跟踪程序的运行流程,观察哪条语句执行了,哪条语句没有执行。
满足暂停程序、观察变量和逐条执行语句等功能的工具和方法总称为程序调试。
5.3.3 如何进行程序调试
问题:顺序输出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所示。
图5.13 bug和程序调试
“bug” 这个单词本身是“虫子”的意思,将计算机程序中的错误或缺陷称为bug是有原因的。在电子管计算机的年代,一台计算机的主机重达数吨,常常占据整个房间。在某个实验室的某个早晨,这台计算机突然停止了工作,我们的IT前辈马上开始寻找出现这种情况的原因。凭借设计图样的引导,他们很快就圈定了可能发生问题的位置。在后来的检查中,他们发现原来是一只虫子在爬过两只继电器时造成了短路。在修复了计算机并重新开始工作之后,负责计算机维护的工程师把这次故障记录在一份备忘录上,以便将来其他人遇到类似的情况时可以迅速地找到答案。他还写了一份文档给计算机的设计人员,希望以后在主机的散热孔处加装一层更加细密的金属网,既不影响散热,又可以防止虫子爬到主机里。
因此,人们把计算机系统中的缺陷称为bug,这个名词一直从计算机硬件故障沿用到了计算机软件故障。
大家在以后的编程过程中,一定要仔细认真。如果出现了 bug且不好确定它的位置,可使用程序调试,通过设置断点并单步执行,找到问题所在,最后修改程序。