第3章 流程控制
程序执行的顺序并不会像南北直接贯通的高速公路那样,可以从北到南一路通到底,事实上程序执行的顺序可能复杂到像云贵高原的公路,九弯十八转,容易让人晕头转向,因此程序的控制流程就像为公路系统设计的四通八达的通行指示方向,如图3-1所示。Java的流程控制一般是按照程序源代码的顺序自上而下按序执行的,不过有时也会根据需要来改变程序执行的顺序,此时就是通过流程控制语句或指令来告诉计算机应该优先以哪一种顺序来执行程序,程序设计语言中的基本流程控制结构有三种,分别是顺序结构、选择结构和重复结构。本章将介绍Java语言中关于“流程控制”的使用方法。
本章的学习目标
- 程序的流程结构
- 条件结构
- switch条件选择语句
- 条件运算符
- 循环结构
- 跳转控制语句
3.1 认识流程控制
Java虽然是一种纯粹的面向对象的程序设计语言,但它仍然提供结构化程序设计的基本流程结构,现在分别介绍如下。
1.顺序结构
顺序结构是以程序的第一行语句为入口点,自上而下(Top-Down)执行到程序的最后一行语句。顺序结构在整个程序中没有特殊的流程、分支或跳转,大部分的程序都是按照这种结构化模块(Module)来设计的,如图3-2所示。
2.选择结构
选择结构是使用“条件判断”表达式的运算结果来决定程序的流程,如果条件成立,就执行一个流程分支;如果条件不成立,就执行另一个流程分支。不过,对于选择结构要注意的是,无论是条件成立的流程分支还是条件不成立的流程分支,它们流程结束的最终出口都是同一个,如图3-3所示。if、switch条件语句是选择结构的典型代表。
3.重复结构
重复结构是一种循环控制,根据所设立的条件重复执行某一段程序语句,直到条件不成立,才会结束循环。重复结构的流程图如图3-4所示。
参考图3-4,“条件判断”表达式成立时,则进入程序语句1(statement)的分支流程,就是进入重复结构内(循环体内),执行完循环体内的程序语句后再次进入“条件判断”部分,直到条件不成立时才进入程序语句2(statement),重复结构之外表示结束循环结构了,到循环体之外了。for、while或do-while是程序设计语言中循环结构的典型代表。
3.2 条件选择语句与条件运算符
Java语言中有if和switch两种条件选择语句。if条件语句是各种程序设计语言中常见的条件选择语句,就是根据所指定的“条件判断表达式”进行判断,用判断的结果来决定程序该执行哪一个程序分支。if条件语句分为三种,分别是if、if-else和if-else-if语句,表3-1所示是它们的语法。
3.2.1 if相关语句
if条件选择语句只有在“条件判断表达式”的结果是true时(条件成立时),才会选择进入其中的“程序语句区块”(或称为程序语句片段);如果条件不成立(条件判断表达式的结果为false),就会跳离if条件选择语句。if语句的语法如下:
if (条件判断表达式) {// 条件判断表达式可以是“比较两者之间的关系”,或者复杂的“条件表达式”
程序语句区块;
}
当if的条件判断表达式结果为true时,才会执行“程序语句区块”的部分;如果条件判断表达式的结果是false,就不会执行“程序语句区块”的部分。
例如:
if (a < b) {
System.out.println ("比较结果正确");
}
又如若要判断a的值比0大,则打印输出“正整数”,语句如下:
if (a >0) {
System.out.println ("正整数");
}
【范例程序:CH03_01】
01 /*文件:CH03_01.java
02 *说明:if条件选择语句
03 */
04
05 public class CH03_01 {
06 public static void main(String[] ages) {
07
08 //if条件选择语句使用范例
09 int Tim=20,Tracy=23;
10 System.out.println("Tim年龄="+Tim+",Tracy年龄="+Tracy);
11
12 if (Tim<Tracy){
13 System.out.println("Tim年龄比Tracy小"+'\n');
14 }
15
16 Tim=25;
17 System.out.println("Tim年龄="+Tim+",Tracy年龄="+Tracy);
18 if (Tim>Tracy){
19 System.out.println("Tim年龄比Tracy大"+'\n');
20 }
21
22 Tim=23;
23 System.out.println("Tim年龄="+Tim+",Tracy年龄="+Tracy);
24 if (Tim==Tracy){
25 System.out.println("Tim年龄和Tracy一样");
26 }
27 }
28 }
【程序的执行结果】
程序的执行结果可参考图3-5。
【程序的解析】
第09行:声明变量Tim和Tracy,并赋予初始年龄,Tim是20岁、Tracy是23岁。
第12行:if条件选择语句的条件判断表达式为“Tim第16行:更改Tim的年龄,将Tim赋值为25,即25岁。if条件选择语句的条件判断表达式为“Tim>Tracy”,如果该条件成立(true),就显示“Tim年龄比Tracy大”;如果该条件不成立(false),就不再继续往下执行if条件选择语句(第18~20行的程序代码),离开此段程序代码,继续往下执行。
第22行:更改Tim的年龄,将Tim赋值为23,即23岁。if条件选择语句的条件判断表达式为“Tim==Tracy”,如果该条件成立(true),就显示“Tim年龄和Tracy一样”;如果该条件不成立(false),就不再继续往下执行if条件选择语句(第24~26行的程序代码),离开此段程序代码。
3.2.2 if-else相关语句
在3.2.1小节的if条件选择语句中,只有条件成立才会执行“{”和“}”大括号内的语句,如果条件不成立,就跳出if条件选择语句,没有任何打印输出的内容。但是,如果条件不成立时有另外的程序执行分支,就可以考虑使用if-else条件选择语句。例如,当if条件判断表达式结果为true时,执行“程序语句区块(1)”;当条件判断表达式结果为false时,执行“程序语句区块(2)”。if-else条件选择语句的语法如下:
【if-else条件选择语句的语法】
if (条件判断表达式) {
程序语句区块 (1);
}
else {
程序语句区块 (2);
}
例如要设计一段程序代码,如果a的值比b的值小,就打印输出“比较结果正确”;否则打印输出“比较结果不正确”,这段程序代码的编写如下:
if (a < b) {
System.out.println ("比较结果正确") ;
}else {
System.out.println ("比较结果不正确") ;
}
值得注意的是“程序语句区块”定义的问题,也就是大括号的标示问题,尤其是else之后的程序语句区块部分要记得加上大括号的标示,否则无法正确执行。
【范例程序:CH03_02】
01 /*文件:CH03_02.java
02 *说明:if-else条件选择语句
03 */
04
05 public class CH03_02{
06 public static void main(String[] ages) {
07
08 //if-else条件选择语句使用范例
09 int Tim=27,Tracy=23;
10 System.out.println("Tim年龄="+Tim+",Tracy年龄="+Tracy);
11
12 if (Tim<Tracy) {
13 System.out.println("Tim年龄比Tracy小"+'\n');
14 }else {
15 System.out.println("Tim年龄比Tracy大");
16 }
17 }
18 }
【程序的执行结果】
程序的执行结果可参考图3-6。
【程序的解析】
第12行:条件判断表达式为“Tim第14行:加入else的语句,增加了条件不成立时的程序执行分支,加强了判断结果的明确性。
3.2.3 if-else-if相关语句
if-else-if条件选择语句是if条件选择语句的变形,用来判断多个条件。此条件选择语句可以使用else if判断多个条件,当其中某个if条件判断表达式为true时,就会执行它对应的程序语句区块。if-else-if语句执行条件判断表达式的顺序是自上而下,每次遇到if语句就需要进行“条件判断”,如果一直到最后所有的if语句都不成立,就执行最后一个else的程序语句区块。这种用法可以指定需要判断的各种情况,也能了解当条件不成立时原因为何。if-else-if条件选择语句的语法如下:
if (条件判断表达式) {
程序语句区块 (1);
}else if (条件判断表达式) {
程序语句区块 (2);
}else {
程序语句区块 (3);
}
例如:
if (a < b) {
System.out.println ("比较结果正确 a<b") ;
}else if (a>b) {
System.out.println ("比较结果正确 a>b") ;
} else {
System.out.println ("两个数值相同") ;
}
【范例程序:CH03_03】
01 /*文件:CH03_03.java
02 *说明:if-else-if条件选择语句(1)
03 */
04
05 public class CH03_03 {
06 public static void main(String[] ages) {
07
08 //if-else-if条件选择语句使用范例
09 int Tim=27,Tracy=23;
10 System.out.println("Tim年龄="+Tim+",Tracy年龄="+Tracy);
11
12 if (Tim<Tracy){
13 System.out.println("Tim年龄比Tracy小"+'\n');
14 }else if (Tim>Tracy){
15 System.out.println("Tim年龄比Tracy大"+'\n');
16 }else{
17 System.out.println("Tim和Tracy年龄相同");
18 }
19
20 Tim=23;
21 System.out.println("Tim年龄="+Tim+",Tracy年龄="+Tracy);
22 if (Tim<Tracy){
23 System.out.println("Tim年龄比Tracy小"+'\n');
24 }else if (Tim>Tracy){
25 System.out.println("Tim年龄比Tracy大"+'\n');
26 }else{
27 System.out.println("Tim和Tracy年龄相同");
28 }
29 }
30 }
【程序的执行结果】
程序的执行结果可参考图3-7。
【程序的解析】
第20行:设置Tim的年龄为23岁,和Tracy相同。于是条件判断的结果一直到第26行程序语句才得知,两人的年龄既没有“Tim比Tracy大”,也没有“Tim比Tracy小”,则最终的结果显示为“Tim和Tracy年龄相同”。
我们再来看另一个例子。
【范例程序:CH03_04】
01 /*文件:CH03_04.java
02 *说明:if-else-if条件选择语句(2)
03 */
04
05 public class CH03_04{
06 public static void main(String[] ages){
07
08 //变量声明
09 int score=88;
10 System.out.println("Tim学期成绩总分="+score);
11 //if-else-if条件选择语句使用范例
12 if(score>=90){
13 System.out.println("测验得分等级:A"+'\n');
14 }else if((score>=70)&&(score<90)){
15 System.out.println("测验得分等级:B"+'\n');
16 }else{
17 System.out.println("测验得分等级:C"+'\n');
18 }
19
20 score=60;
21 System.out.println("Tracy学期成绩总分="+score);
22 if(score>=90){
23 System.out.println("测验得分等级:A"+'\n');
24 }else if((score>=70)&&(score<90)){
25 System.out.println("测验得分等级:B"+'\n');
26 }else{
27 System.out.println("测验得分等级:C"+'\n');
28 }
29 }
30 }
【程序的执行结果】
程序的执行结果可参考图3-8。
【程序的解析】
第12~18行:如果学期总成绩(score)为88分,那么换算成等级应该属于什么等级?“score>=90”为等级A、“70<=score<90”为等级B、“score<=70”为等级C。
第14、24行:对于“70<=score<90”的描述,使用AND(&&)逻辑运算符。
3.2.4 嵌套if语句
嵌套if语句是指“内层”的if语句是另一个“外层”if的子语句,此子语句可以是if语句、else语句或者if-else语句。
【嵌套if条件选择语句的语法】
if (条件判断表达式1) {
程序语句区块 (1);
if (条件判断表达式2) {
程序语句区块 (2);}
else {
程序语句区块 (3);
}
}
【范例程序:CH03_05】
01 /*文件:CH03_05.java
02 *说明:嵌套if语句
03 */
04
05 public class CH03_05{
06 public static void main(String[] ages){
07
08 //变量声明
09 int a=0,b=0;
10 System.out.println("AND逻辑门=("+a+","+b+")");
11 if (a==1){
12 if (b==1){
13 System.out.println(a+"(AND)"+b+"="+"1"+'\n');
14 }
15 else{
16 System.out.println(a+"(AND)"+b+"="+"0"+'\n');
17 }
18 }
19 else{
20 System.out.println(a+"(AND)"+b+"="+"0"+'\n');
21 }
22 a=1;
23 System.out.println("AND逻辑门=("+a+","+b+")");
24 if (a==1){
25 if (b==1){
26 System.out.println(a+"(AND)"+b+"="+"1"+'\n');
27 }
28 else{
29 System.out.println(a+"(AND)"+b+"="+"0"+'\n');
30 }
31 }
32 else{
33 System.out.println(a+"(AND)"+b+"="+"0"+'\n');
34 }
35 a=1;
36 b=1;
37 System.out.println("AND逻辑门=("+a+","+b+")");
38 if (a==1){
39 if (b==1){
40 System.out.println(a+"(AND)"+b+"="+"1"+'\n');
41 }
42 else{
43 System.out.println(a+"(AND)"+b+"="+"0"+'\n');
44 }
45 }
46 else{
47 System.out.println(a+"(AND)"+b+"="+"0"+'\n');
48 }
49 }
50 }
【程序的执行结果】
程序的执行结果可参考图3-9。
【程序的解析】
判断AND逻辑运算的结果。只有当参与AND逻辑运算的两个操作数同为1时,AND逻辑运算的结果才为1;其他组合的逻辑运算结果都为0。
第09~48行:若a=1且b=1,则显示结果为1,其余组合则显示结果为0。
3.2.5 switch条件选择语句
在进行多重选择的时候,过多if-else-if条件选择语句的嵌套会造成程序维护上的困扰。在Java语言中提供了switch条件选择语句,使用它可以让程序更加简洁清楚。与if条件选择语句不同的是,switch只有一个条件判断表达式。switch是一种多选一的条件选择语句,它是按照条件判断表达式的运算结果来决定在多个程序分支中选择其中之一的程序分支,并执行这个程序分支内的程序代码。switch条件选择语句的语法如下:
switch (表达式) {
case 数值1;
语句1;
break;
case 数值2;
语句2;
break;
default:
语句3;
}
在switch条件选择语句中,如果找到了case后面匹配的结果值,就会执行该case程序区块内的程序语句,当执行完这个case程序区块中的程序语句之后,程序流程并不会直接离开switch语句,还会往下继续执行其他case语句与default语句,这样的情况被称为“贯穿”(Falling Through)现象。
因此,我们通常在每个case程序区块后面加上break语句来结束switch语句,这样才可以避免“贯穿”的情况。至于default语句,我们可以把它放在switch语句的任何位置,表示如果找不到任何匹配的结果值,最后就要执行default语句。此外,如果default语句摆在所有case语句的最后,就可以省略default程序区块最后的break语句,否则就必须加上break语句来结束switch语句。另外,在switch语句中的花括号绝不可省略,这是“事故多发地”(程序容易出错的地方)。
如图3-10所示是switch 条件选择语句的流程图。
假如要从期末排名给予对应的奖励,使用switch条件选择语句的语法如下:
switch (期末排名) {
case 第一名:
出国旅行;
break;
case 第二名:
国内旅行;
break;
case 第三名:
购书礼券;
break;
default:
要多努力;
}
在上述的程序代码中,若排名是第一名,则获得的奖励是“出国旅行”;若排名是第二名,则获得的奖励是“国内旅行”;若排名是第三名,则获得的奖励是“购书礼券”;但若名次不在前三名,则没有奖励。
【范例程序:CH03_06】
01 /*文件:CH03_06.java
02 *说明:switch条件选择语句
03 */
04
05 public class CH03_06{
06 public static void main(String[] ages){
07
08 //变量声明
09 char math_score='A';
10 System.out.println("Michael数学成绩:"+math_score);
11 switch(math_score){
12 case'A':
13 System.out.println("老师评语:非常好!真是优秀!"+'\n');
14 break; // break的作用是跳离switch条件选择语句
15 case'B':
16 System.out.println("老师评语:也不错,但还可以更好!"+'\n');
17 break; // break的作用是跳离switch条件选择语句
18 case'C':
19 System.out.println("老师评语:真的要多用功!"+'\n');
20 break; // break的作用是跳离switch条件选择语句
21 default:
22 System.out.println("老师评语:不要贪玩,为自己多读书!"+'\n');
23 }
24
25 math_score='C';
26 System.out.println("Jane数学成绩:"+math_score);
27 switch(math_score){
28 case'A':
29 System.out.println("老师评语:非常好!真是优秀!"+'\n');
30 break; // break的作用是跳离switch条件选择语句
31 case'B':
32 System.out.println("老师评语:也不错,但还可以更好!"+'\n');
33 break; // break的作用是跳离switch条件选择语句
34 case'C':
35 System.out.println("老师评语:真的要多用功!"+'\n');
36 break; // break的作用是跳离switch条件选择语句
37 default:
38 System.out.println("老师评语:不要贪玩,为自己多读书!"+'\n');
39 }
40 }
41 }
【程序的执行结果】
程序的执行结果可参考图3-11。
【程序的解析】
第09行:声明存储数学成绩的变量math_score,并赋初值。
第11~23行:switch语句的条件判断表达式为math_score,若math_score=A,则显示“老师评语:非常好!真是优秀!”;若math_score=B,则显示“老师评语:也不错,但还可以更好!”;若math_score=C,则显示“老师评语:真的要多用功!”;若math_score不是A或B或C,则显示“老师评语:不要贪玩,为自己多读书!”。
每一个case程序语句区块结束位置都会加上break语句,目的是说明如果已经满足该case的条件,其余的case条件就不需要再进行比较,可以离开switch语句了。
3.2.6 条件运算符
条件运算符(Conditional Operator)是一个三元运算符(Ternary Operator,或称为三目运算符),它和if else条件选择语句的功能一样,可以用来替代简单的if else条件选择语句,让程序代码看起来更为简洁,它的语法格式如下:
条件判断表达式?程序语句一:程序语句二;
如果条件判断表达式成立,就会执行程序语句一;否则执行程序语句二。不过使用条件运算符只允许单行语句,例如:
str = ( num>=0 )? "正数":"负数"
等号的右边是“条件判断表达式”,问号“?”表示if,冒号“:”表示else。因此,上面的范例说明:如果num的值大于等于0,就显示“正数”,否则显示“负数”。
【范例程序:CH03_07】
01 /*文件:CH03_07.java
02 *说明:条件运算符
03 */
04
05 public class CH03_07{
06 public static void main(String[] ages){
07
08 //变量声明
09 int math_score=70;
10 System.out.println("Michael数学成绩:"+math_score);
11 String str;
12 str=(math_score>80)?"非常好!":"多加油!";
13 System.out.println("老师评语:"+str+'\n');
14
15 math_score=90;
16 System.out.println("Jane数学成绩:"+math_score);
17 str=(math_score>80)?"非常好!":"多加油!";
18 System.out.println("老师评语:"+str+'\n');
19 }
20 }
【程序的执行结果】
程序的执行结果可参考图3-12。
【程序的解析】
第11行:声明用于存储结果的字符串变量。
第12行:意思是指:如果成绩高于80,老师的评语为“非常好!”;如果成绩低于80,老师的评语为“多加油!”。
使用条件运算符的方式可以减少程序的复杂度,但是它的条件判断功能比较简单,受到限制。
3.3 计数循环与条件循环
循环语句属于重复结构中的流程控制语句,当设置的条件符合时,就会执行循环中的程序语句,一旦条件不符合就会跳出循环。循环语句分为for、while和do-while三种。
假如想要让计算机在屏幕上打印出500个字符'*',我们并不需要大费周章地编写500次System.out.print语句,这时只需要使用重复结构即可。Java语言提供了for、while以及do-while三种循环语句来实现重复结构的效果。在尚未开始正式介绍循环语句之前,我们先通过表3-2快速看看这三种循环语句的特性及使用时机。
3.3.1 for循环
for循环又称为计数循环,是程序设计中较常使用的一种循环形式,可以重复执行固定次数的循环。for语句是一种较严谨的循环语句,是一种计数循环(Counting Loop),循环语句中设置有“循环计数变量的起始值”“循环条件”和“循环计数变量的递增或递减表达式”。for语句的声明语法如下:
for (循环计数变量的起始值;循环条件;循环计数变量的递增或递减表达式)
{
程序语句区块;
}
- 循环计数变量的起始值:是for循环第一次开始时循环计数变量的初值。
- 循环条件:当for语句循环的条件结果为false时,循环就会结束。
- 循环计数变量的递增或递减表达式:每轮循环执行后,循环变量要增加或减少的表达式。
for 循环的执行步骤说明如下。
步骤1:设置循环计数变量的起始值。
步骤2:如果循环条件表达式的结果为真(true),就执行for循环体内的程序语句。
步骤3:循环体内的程序语句执行完成之后,增加或减少循环计数变量的值,递增或递减的步长可以根据需求而定,再重复步骤2。
步骤4:如果循环条件表达式的结果为假(false),就结束for循环。
例如:
for (int i=0;i <=5;i++)
{
a=a+1;
}
上面的程序表示:循环计数变量的起始值i=0,重复执行次数是循环条件i<=5成立时,循环变量的递增量是1(步长为1)。若未超出重复执行次数(循环条件依然成立时),则执行“a=a+1”;若i=6,超出了重复执行次数(循环条件i<=5不成立了),则结束for循环。
【范例程序:CH03_08】
01 /*文件:CH03_08.java
02 *说明:for循环应用范例
03 */
04 public class CH03_08{
05 public static void main(String args[]){
06 System.out.println("计算1~10之间所有奇数的和");
07 int sum=0;//声明存储奇数总和的变量,并赋初值为0
08 System.out.println("1~10之间所有的奇数为:");
09 for(int i=1; i<=10;i++){
10 if(i%2!=0){//使用if语句判断i是否为奇数
11 sum+=i;
12 System.out.print(i+" ");
13 }
14 }
15 System.out.println();
16 System.out.println("答案="+sum);//输出答案
17 }
18 }
【程序的执行结果】
程序的执行结果可参考图3-13。
【程序的解析】
第10行:使用i%2的结果判断i是否为奇数,当i为奇数时i%2的结果应该为1。
第09~14行:是for循环。循环条件“i<=10”表示循环总共要执行11次,因为i一直增加到11时,“i<=10”的循环条件就不成立了,即达到循环结束的条件。所以当i=11时,就不会再进入for循环体,第10~13行的程序代码共执行了10次。
3.3.2 嵌套for循环
所谓嵌套for循环,就是多层的for循环结构。在嵌套for循环结构中,执行流程必须先等内层循环执行完毕,才会逐层继续执行外层循环。注意容易犯错的地方是内外循环间不可交错。嵌套for循环的典型应用例子是“九九乘法表”。嵌套for语句的语法如下:
for ( 外层循环的计数变量起始值;循环条件;计数变量的递增或递减值 ) {
for ( 内层循环的计数变量起始值;循环条件;计数变量的递增或递减值 ) {
程序语句区块;
}
};
【范例程序:CH03_09】
01 /*文件:CH03_09.java
02 *说明:嵌套for循环应用范例
03 */
04
05 public class CH03_09{
06 public static void main(String[] ages){
07 for (int i=1;i<=9;i++){
08 for (int j=1;j<=9;j++){
09 System.out.print(i+"*"+j+"="+i*j+'\t');
10 }
11 System.out.print('\n');
12 }
13 }
14 }
【程序的执行结果】
程序的执行结果可参考图3-14。
3.3.3 while循环
如果循环执行的次数可以确定,那么for循环就是最佳的选择。对于那些不能确定循环次数的循环,while循环就可以派上用场了。while循环与for循环类似,都属于前测试型循环。前测试型循环的工作方式是在循环体开始执行前必须先检查循环条件表达式,当表达式结果为真(true)时,才会执行循环体内的程序语句;如果循环条件表达式结果为假(false),就会结束循环。While循环语句的语法如下:
while (循环条件表达式 )
{
循环体内的程序语句;
循环条件变量的变化;
}
如图3-15所示为while循环的流程图。
当while语句的循环条件表达式的结果为真(true)时,就会重复执行循环体内的程序语句,直到循环条件表达式的结果为假(false),才会结束while循环。在进行while循环时,通常会先在while循环之前加上一个变量并赋初值,用于控制while循环的变量,在while循环体内根据循环的需要更改这个变量的值,以便在执行新一轮循环前用来测试循环条件是否成立,例如:
while (i<=10 )
{
a=i+1;
i++; //更改循环变量的值
}
While语句括号内的部分是“循环条件”,“i<=10”表示只有i值小于等于10,才能够进入while循环体内,执行“a=i+1”,而后更改循环变量i的值(在此例中是用i++递增的)。
【范例程序:CH03_10】
01 /*文件:CH03_10.java
02 *说明:while循环应用范例
03 */
04 public class CH03_10{
05 public static void main(String args[ ]){
06 int n=1,sum=0;//声明while循环变量n并赋初值,声明存储累加值的变量sum
07 //while循环开始
08 while(n<=10){
09 System.out.print("n="+n);
10 sum+=n;//计算n的累加值
11 System.out.println("\t累加值="+sum);
12 n++;
13 }
14 System.out.println("循环结束");
15 }
16 }
【程序的执行结果】
程序的执行结果可参考图3-16。
【程序的解析】
第08行:n<=10是while语句的循环条件表达式,当该表达式的结果为真(true)时,就会重复执行循环体内的程序语句。
第12行:将计数器n递增1,再回到第08行检查循环条件是否依然成立,如果表达式结果为假(false),就会结束这个while循环,继续执行while循环体后面的第14行程序语句。
3.3.4 do-while循环
do-while循环是先执行循环体内的程序语句,再测试循环条件是否成立,这与之前的for循环、while循环不同。do-while循环属于“后测型”循环,for循环、while循环属于“前测型”循环。do-while循环无论如何都会执行一次循环体内的程序语句,再测试循环条件是否成立,如果成立,就返回循环起点,重复执行循环体内的程序语句。
do-while循环与while循环类似,两者的差别就是循环条件表达式所在的位置有前后之分。do-while循环语句的语法如下:
do {
循环体内的程序语句;
循环条件变量的变化;
} while (循环条件表达式);
【范例程序:CH03_11】
01 /*文件:CH03_11.java
02 *说明:do-while循环应用范例
03 */
04 public class CH03_11{
05 public static void main(String args[]){
06 int n=40,m=180;
07 int temp=0;//作为n与m值互换的中间暂存变量
08 System.out.println("n="+n+",m="+m);
09 //do-while循环开始
10 do{
11 temp=m%n;
12 m=n;
13 n=temp;
14 }while(n!=0 );//检查循环条件表达式
15 System.out.println("两个数的最大公约数="+m);
16 }
17 }
【程序的执行结果】
程序的执行结果可参考图3-17。
【程序的解析】
第11行:将m%n的运算结果(余数)赋值给temp,此处m的值必须大于n的值。
第12~13行:借助中间暂存变量temp将n与m的值对调,因为此时n的值大于m的值。
3.3.5 无限循环
在循环语句中设置循环条件表达式时,必须注意不能使循环条件永远成立,否则就会形成无限循环(或称为死循环)。下面列出几个常见的无限循环的例子,请大家在编写循环语句的时候避免出现无限循环。
while(true){ } //while语句中的循环条件永远为true
for(;;){ } //for语句中没有设置任何循环条件
for(int i=1;i>0;i++){ } //循环条件与初始值相比较永远成立
3.4 控制跳转语句
控制跳转语句(Control Jump Statement)是Java语言中与循环语句搭配使用的一种流程控制语句,控制跳转语句的使用能让循环的流程控制有更多的变化。控制跳转语句有break、continue和return三种语句。
3.4.1 break语句
在介绍switch语句时提到过break语句,使用它可以跳离switch语句,继续执行switch语句后的其他程序语句。不过,break语句不仅可以搭配switch语句,还可以和循环语句搭配使用。break是“中断”的意思,break语句可以中断循环的执行并跳转到标签(Label)语句定义的一段程序语句区块,类似于C++语言中的goto语句。break语句的语法如下:
标签名称:
程序语句;
……
break 标签名称;
事先建立好break的标签位置及名称,当程序执行到break的程序代码时,就会根据所定义的break标签名称跳转到标签指定的地方。
【范例程序:CH03_12】
01 /*文件:CH03_12.java
02 *说明:break语句应用范例
03 */
04 public class CH03_12{
05 public static void main(String args[]){
06 int i ,j;
07 System.out.println("跳离一层循环");
08 for(i=1; i<10; i++){
09 for(j=1; j<=i; j++){
10 if(j==5) break ;//跳离一层循环
11 System.out.print(j);
12 }
13 System.out.println();
14 }
15 System.out.println();
16
17 System.out.println("跳离双层循环");
18 out1://设置标签
19 for(i=1; i<10; i++){
20 for(j=1; j<=i; j++){
21 if(j==5) break out1;//跳转到标签处
22 System.out.print(j);
23 }
24 System.out.println();
25 }
26 System.out.println();
27 }
28 }
【程序的执行结果】
程序的执行结果可参考图3-18。
【程序的解析】
第10行:此处的break语句只会跳离第9~12行的for循环(内层循环)。
第8~14行:执行过程如下:
i=1→j=1→显示结果:1。
i=2→j=1~2→显示结果:12。
i=3→j=1~3→显示结果:123。
……
i=5→j=1~5→显示结果:1234(不会显示5,因为已经跳离循环)。
i=6→j=1~6→显示结果:1234。
……
i=9→j=1~9→显示结果:1234。
i=10(i<10不成立,结束循环)。
第18行:设置break语句要跳转的标签位置及名称(out1):
break out1;程序语句,会跳出第19~25的双层循环。
i=1→j=1→显示结果:1。
i=2→j=1~2→显示结果:12。
i=3→j=1~3→显示结果:123。
……
i=5→j=1~5→显示结果:1234(不会显示5,而且已经跳离循环,跳转到第18行程序代码最外层循环的位置,并且结束循环)。
3.4.2 continue语句
continue 语句的功能是强制for、while、do-while等循环语句终止当前这一轮的循环,而将控制权转移到循环开始处进行下一轮循环,也就是跳过本轮循环中尚未执行的语句,开始执行下一轮的循环。continue是“继续”的意思,continue 语句与 break 语句最大的差别在于continue 只是跳过它之后未执行的语句,但并未跳离循环。continue语句也可以配合标签指令改变程序执行的流程。
【范例程序:CH03_13】
01 /*文件:CH03_13.java
02 *说明:continue语句应用范例
03 */
04 public class CH03_13{
05 public static void main(String args[]){
06 int i ,j;
07 for(i=1; i<10; i++){
08 for(j=1; j<=i; j++){
09 if(j==5) continue ;//跳过下面的程序语句继续执行下一轮循环
10 System.out.print(j);
11 }
12 System.out.println();
13 }
14 System.out.println();
15 out1:
16 //设置标签
17 for(i=1; i<10; i++){
18 for(j=1; j<=i; j++){
19 if(j==5) continue out1;//跳转到标签处继续执行
20 System.out.print(j);
21 }
22 System.out.println();
23 }
24 System.out.println();
25 }
26 }
【程序的执行结果】
程序的执行结果可参考图3-19。
【程序的解析】
第09行:当程序执行到j==5时,会跳过第10行,从第8行的循环开始执行下一轮循环。
第07~13行:执行过程如下:
i=1→j=1→显示结果:1。
i=2→j=1~2→显示结果:12。
i=3→j=1~3→显示结果:123。
……
i=5→j=1~5→显示结果:1234(不会显示5,因为continue语句会跳过第10行程序代码)。
i=6→j=1~6→显示结果:12346。
……
i=9→j=1~9→显示结果:12346789。
i=10(i<10不成立,结束循环)。
第19行:continue语句加上标签会直接跳过第20行程序语句,从第15行继续执行。
第17~23行:执行过程如下:
i=1→j=1→显示结果:1。
i=2→j=1~2→显示结果:12。
i=3→j=1~3→显示结果:123。
i=4→j=1~4→显示结果:1234。
i=5→j=1~5(不会显示5,而且跳转到第15行程序代码continue语句标签处,开始执行下一轮for循环。因为第20行的输出显示没有换行,所以输出结果彼此相连)。
因此,直到i=9→j=1~9→显示结果:12341234123412341234(从结果可以看出共有5组1234第一组是i=5的显示结果;第二组是i=6的显示结果;第三组是i=7的显示结果;第四组是i=8的显示结果;第五组是i=9的显示结果)。
3.4.3 return语句
return语句可以终止程序当前所在的方法(Method)回到调用方法的程序语句。在面向过程的程序设计语言中,return作为函数调用的返回语句,我们可以把面向对象程序设计语言中的方法(Method)理解成函数(Function)。使用return语句时,可以将方法中的变量值或表达式运算的结果值返回给调用的程序语句,不过返回值的数据类型要和声明的数据类型相符合,如果方法不需要返回值,那么可以将方法声明为void数据类型。以下是return语句的使用方法。
【return语句的语法】
return 变量或表达式;
return; // 没有返回值
【范例程序:CH03_14】
01 /*文件:CH03_14.java
02 *说明:return语句应用范例
03 */
04 public class CH03_14{
05 public static void main(String args[]){
06 int ans;
07 ans=sum(10);//调用sum方法
08 System.out.println("1~10的累加");
09 System.out.println("ans="+ans);
10 }
11
12 //sum方法
13 static int sum(int n){
14 int sum=0;
15 for(int i=1; i<=n; i++){
16 sum+=i;
17 }
18 return sum; //返回sum变量的值
19 }
20 }
【程序的执行结果】
程序的执行结果可参考图3-20。
【程序的解析】
第07行:用变量ans来接收sum方法返回的值,其中10为传递的实际参数。
第13~19行:sum()方法的定义区块,将该方法声明为static,可以直接被调用和执行,而不必通过类对象的方式。
3.4.4 for-each的for循环
for-each循环和传统for循环不同的地方是,for-each可以直接读取“集合(Set)类型”的数据,如数组。for-each可以使循环自动化,不用编程人员动手设置循环的计数值、起始值和循环条件(或循环终止值),也不用设置“数组的索引值”,好处是避免索引值超过数组边界而造成错误。for-each语句的语法如下:
for(变量名称:集合类型){
程序语句区块;
}
下面举个例子来说明。假如A是一个数组,其元素的内容或值是整数类型的。如果要读取数组中元素的值,一般的方式是使用传统for循环来执行读取的操作,而读取数组元素是通过“索引值”(也称为数组的“下标值”),但是这种方式的风险是可能会引发索引值超过数组边界的错误。
for-each改变了传统的做法,当进入for-each循环时,读取方式不再是通过索引值,而是直接读取数组中的元素值,因此第一次进入循环,x=1,这个1不是指数组的索引值,而是指元素值。所以x是否声明成整数类型(int)要由数组来决定。图3-21中的两个图对比了传统for循环与for-each循环读取上的不同之处。
对比语法,“int x”就是“变量名称”部分,“A”就是“集合类型”部分,集合类型指的是所声明的数组。
【范例程序:CH03_15】
01 /*文件:CH03_15.java
02 *说明:for-each循环应用范例
03 */
04
05 public class CH03_15{
06 public static void main(String[] ages){
07 int A[]={1,2,3,4,5,6,7,8,9};
08 char B[]={'H','a','p','p','y'};
09 System.out.println("数字数组"); // 用传统for循环读取数组元素
10 for (int i=0;i<A.length;i++){
11 System.out.print(A[i]+" ");
12 }
13 System.out.println('\n');
14 System.out.println("字符数组");
15 for (int i=0;i<B.length;i++) {
16 System.out.print(B[i]+" ");
17 }
18 System.out.println('\n');
19 System.out.println("数字数组"); // 用for-each循环读取数组元素
20 for (int i:A){
21 System.out.print(i+" "); //直接读取数组中的元素值
22 }
23 System.out.println('\n');
24 System.out.println("字符数组");
25 for (char i:B){
26 System.out.print(i+" ");// 因为数组B的元素值是字符,
所以i必须声明成char 数据类型
27 }
28 System.out.println('\n');
29 }
30 }
【程序的执行结果】
程序的执行结果可参考图3-22。
【程序的解析】
第20行:for-each循环读取数组中的元素值,在for-each声明中的“变量”的数据类型是由数组的元素决定的。“变量”的属性是“只读的”,意思就是只能读取的属性,不能更改或写入的属性。
如果是多维数组,那么将如何使用for-each循环呢?下面通过范例程序来实现多维数组的for-each循环的用法。
【范例程序:CH03_16】
01 /*文件:CH03_16.java
02 *说明:for-each——读取多维数组的应用范例
03 */
04
05 public class CH03_16{
06 public static void main(String[] ages){
07 int A[][]=new int[2][3]; //声明多维数组
08 for (int i=0;i<2;i++){ //给数组中的元素赋值,并且读取数组元素值
09 for (int j=0;j<3;j++){
10 A[i][j]=i+j;
11 System.out.print(A[i][j]+" ");
12 }
13 }
14 System.out.println('\n');
15 for (int i[]:A){ // 改用for-each循环读取数组元素值
16 for (int j:i){
17 System.out.print(j+" ");
18 }
19 }
20 System.out.println('\n');
21 }
22 }
【程序的执行结果】
程序的执行结果可参考图3-23。
【程序的解析】
第15~19行:二维数组其实就是数组中的数组。因此,在第15行的外层循环,int i[ ]表示读取的是一整组的一维数组,在第16行的内层循环则是针对外层循环所指定的一维数组读取其中的元素值。
3.5 高级应用练习实例
本章主要讨论了Java的三种基本流程控制结构及其相关的语句,它们是顺序结构、选择结构与重复结构。下面通过本节的综合练习让大家对本章所讲述的内容有更深入的认识。
3.5.1 使用条件选择语句进行考试成绩的评级
条件选择语句根据测试条件选择性地执行某些分支的程序语句区块,它包含两种不同作用的流程控制语句:if…else与switch…case条件选择语句。两者最大的差异在于:switch...case语句只能引入一个参数,也就是说它无法执行“比较”与“判断”的操作。下面的范例程序综合运用上述两种流程控制语句来完成某项考试成绩的评级工作。
【综合练习】使用条件选择语句进行考试成绩的评级
01 //使用条件选择语句进行考试成绩的评级
02 class WORK03_01 {
03 public static void main(String args[]) {
04 int score = 88;
05 int level = 0;
06 //嵌套if…else语句
07 System.out.println("使用if...else语句进行判断");
08 if (score >= 60) {
09 if(score >= 75) {
10 if(score >= 90) {
11 System.out.println("成绩" + score + " 是甲等!");
12 level = 1;
13 }
14 else {
15 System.out.println("成绩" + score + " 是乙等!");
16 level = 2;
17 }
18 }
19 else {
20 System.out.println("成绩" + score + " 是丙等!");
21 level = 3;
22 }
23 }
24 else
25 System.out.println("成绩" + score + " 不及格!");
26 // switch…case语句
27 System.out.println("使用switch...case语句判断");
28 switch(level) {
29 case 1:System.out.println("成绩" + score + " 是甲等!");break;
30 case 2:System.out.println("成绩" + score + " 是乙等!");break;
31 case 3:System.out.println("成绩" + score + " 是丙等!");break;
32 default:System.out.println("成绩" + score + " 是丁等!");break;
33 }
34 }
35 }
【程序的执行结果】
程序的执行结果可参考图3-24。
3.5.2 闰年的判断与应用
判断闰年的问题也适合用以上结构来解决,闰年计算的规则是“四年一闰,百年不闰,四百年一闰”。下面的范例程序使用if else if条件选择语句来执行闰年的计算规则,以判断某一年份是否为闰年。
【综合练习】闰年的判断与应用
01 //闰年的判断与应用
02 public class WORK03_02 {
03 public static void main(String args[]) {
04 int year=2008;//声明存储年份的变量,并赋值
05 //声明整数变量
06 if(year % 4 !=0) /*如果year不是4的倍数*/
07 System.out.println(year+" 年不是闰年。"); /*显示year不是闰年*/
08 else if(year % 100 ==0) /*如果year是100的倍数*/
09 {
10 if(year % 400 ==0) /*且year是400的倍数*/
11 System.out.println(year+" 年是闰年。");
12 /*显示year是闰年*/
13 else /*否则*/
14 System.out.println(year+" 年不是闰年。");
15 /*显示year不是闰年*/
16 }
17 else /*否则*/
18 System.out.println(year+" 年是闰年。"); /*显示year是闰年*/
19 }
20 }
【程序的执行结果】
程序的执行结果可参考图3-25。
3.5.3 使用各种循环计算1~50的累加之和
循环常被用来计算某一范围的数字总和。下面的范例程序就是使用三种循环来计算1~50的累加之和。
【综合练习】使用各种循环计算1~50的累加之和
01 //使用各种循环计算1~50的累加之和
02 class WORK03_03 {
03 public static void main(String args[]) {
04 int totalSum = 0;
05 int var1 = 1;
06 int var2 = 1;
07 int var4 = 50;
08 //while循环
09 while(var1 <= var4) {
10 totalSum += var1;
11 var1 += 1;
12 }
13 System.out.println("用while循环计算1至50的累加之和为" + totalSum);
14 totalSum = 0;
15 //do…while循环
16 do {
17 totalSum += var2;
18 var2 += 1;
19 }while(var2 <= var4);
20 System.out.println("do…while循环计算1至50的累加之和为" + totalSum);
21 totalSum = 0;
22 //for循环
23 for (int var3 = 1; var3 <= var4; var3++)
24 totalSum += var3;
25 System.out.println("用for循环计算1至50的累加之和为" + totalSum);
26 }
27 }
【程序的执行结果】
程序的执行结果可参考图3-26。
课后习题
一、填空题
1. 结构是以程序的第一行语句为入口点,自上而下执行到程序的最后一行语句。
2.循环语句分为 、 和 三种。
3. 语句设置了循环起始值、循环条件和每轮循环结束后的递增或递减表达式。
4. 是一种多选一的条件选择语句,它是根据条件表达式的运算结果来决定在多个分支的程序区块中选择执行其中的一个分支程序区块。
5. 语句是指“内层”的if语句是另一个“外层”if的子语句,此子语句可以是if语句、else语句或者if-else语句。
6.while语句是根据循环条件表达式结果的 值来决定是否要继续执行循环体内的程序语句。
7.使用循环语句时,当循环条件永远都成立时,就会形成 。
8.控制跳转语句有 、 和 三种。
9. 语句类似于C++语言中的goto语句。
10.使用 语句可以跳离循环。
11.流程控制可分为 语句与 语句。
12.选择结构使用 语句来控制程序的流程。
13.if语句共分为 、 和 三种。
14. 语句可以从条件表达式的多种结果中选择程序的执行流程。
15. 语句可以终止程序当前所在的方法,回到调用方法的程序语句。
二、问答与实践题
1.试简述结构化程序设计中的基本流程结构。
2.do-while语句和while语句的主要差别是什么?
3.什么是嵌套循环?
4.在下面的程序代码中是否有错误的地方?如果有,请指出。
switch ( ) {
case 'r':
System.out.println("红灯亮:");
break;
case 'g':
System.out.println("绿灯亮:");
break;
default:
System.out.println("没有此信号灯");
}
5.请问下面的语句中变量flag的值是多少?此处假设number=1000。
flag=(number< 500) ? 0 : 1;
6.请问在switch语句中,default指令扮演的角色是什么?
7.请设计一个Java程序,它可以判断所输入的数值是否为7的倍数,其执行的结果可参考图3-27中的输出部分。
8.试着用条件运算符改写第7题。
9.请设计一个Java程序,让用户输入两个数字,然后将这两个数字中较小者的立方值打印输出,程序的执行过程和输出结果可参考图3-28。
10.请设计一个Java程序,求100到200之间的所有奇数之和,程序的执行结果可参考图3-29中的输出部分。
11.请设计一个Java程序,让用户输入一个整数number,当所输入的整数小于1时,就会要求用户重新输入,直到获得一个大于等于1的整数number,然后累加1到number之间的所有奇数,程序的执行过程和结果可参考图3-30。
12.请设计一个Java程序,让用户输入一个整数number,并计算其阶乘值,程序的执行过程和输出结果可参考图3-31。