第4章 程序流程控制
任何一门语言都需要基本的流程控制语句,其思想也符合人类判断问题或做事的逻辑过程。在Java语言中提供了条件语句、分支语句、循环语句和跳转语句。通过本章的学习,读者可以掌握基本的程序流程,为编写面向对象的程序打下基础。在Java中,程序流程的控制体现在方法的设计和实现上。本章将依次介绍各种程序流程控制语句。
本章主要介绍的内容有:
❑条件语句
❑分支语句
❑循环语句
❑跳转语句
4.1 流程控制概述
在面向过程的语言中,程序流程控制是十分重要的内容,因为一个过程总是由各种判断、循环、跳转等实现的。在Java这样面向对象的语言中,仍然不可或缺地需要程序的流程控制,因为对象行为(也称为方法)的实现仍然需要流程控制。
流程控制是任何一门高级开发语言都必须认真面对的问题。学习本章时,要求读者认真学习每一小节的内容,掌握语句的格式和用法,按照书上的例子亲自编写并执行一遍。
4.2 条件语句
在日常生活中,读者可能会遇到类似这样的问题:如果明天天气好,就去爬香山。这里如果就是一个判断关键字、而爬香山就是判断成立时的结果。在程序的流程控制中,条件语句就完成这样的功能。简单条件语句的格式为:
if(条件表达式) 执行语句;
图4.1 简单if语句的流程图
if语句中的“条件表达式”的结果是布尔值,无论条件表达式的形式如何体现,但“( )”内的最终结果是个布尔值。如果布尔值为真(true),则执行“执行语句”;如果“( )”内的布尔值为假(false),则不执行其后的“执行语句”,此时跳出if语句。简单if语句的流程图如图4.1所示。
【范例4-1】代码4-1为简单的条件语句示例程序。
代码4.1 简单的条件语句
1 public class IfTest{ 2 public static void main(String[] args){ 3 int x=2007; 4 int y=2008; 5 if(y>x) 6 System.out.println("y>x and" +"x is :"+x+"y is:"+y); 7 } 8 }
【运行效果】
y>x and x is : 2007 y is: 2008
【代码说明】该段代码首先在第5行判断两个整数x和y的大小,如果y>x则if的条件判断的布尔值为真,则执行紧接下来的输出语句“System.out.println("y>x and"+"x is:"+x+"y is:"+y)”。
4.3 分支语句
上一节介绍了简单的if语句,在日常生活中其实还存在大量的多重判断,例如:如果明天天气好就去爬香山,如果明天阴天就待在家看电影,如果DVD机坏了就安心看书。显然,这里有两个判断,首先是晴天与阴天的判断。其次是阴天的条件下又有一层判断:如果DVD机坏了,就看书。上述说法有些啰嗦,在日常活动中没有人会有意识地去做上述的判断。但事实上,在人类生活的潜意识里确实存在这种逻辑判断,只是与机器相比,人积累了大量的逻辑知识和生活经验,不用有意识地思考就可以随时得出逻辑计算的结果。但是,计算机只知道程序,没有程序指令它就无法工作,所以必须在程序设计语言中设计明确的各种指令格式,来满足实现复杂逻辑判断的能力。本节将重点介绍更复杂的逻辑判断和多分支语句。
4.3.1 简单的if-else语句
简单的if-else语句是多分支语句的一种。其语句的格式为:
if(条件表达式) 执行语句1; else 执行语句2;
如果if条件语句成立,即“()”内的布尔值为真,则执行语句1;否则if条件语句不成立,即“()”内的布尔值为假,则执行语句2。if-else语句实现了一种是非判断,如果“是”做什么,如果“不是”做什么。
【范例4-2】代码4.2实现两个数大小的判断并输出判断结果,如果y>x,则输出“y > x”,否则输出“y<x”。
代码4.2 if-else语句示例程序
1 public class IfElseTest{ 2 public static void main(String[] args){ 3 int x=2007; //第3、4行定义两个整型变量x、y并赋初值 4 int y=2008; 5 if(y>x) //判断是否y>x 6 System.out.println("y>x"); //如果y>x成立,则输出"y>x" 7 else 8 System.out.println("y<x"); //否则输出"y<x" 9 } 10 }
【运行效果】
y>x
【代码分析】第3~4行定义了两个整型变量,第5行比较它们的大小。
4.3.2 if-else多分支语句
简单的if-else语句可以嵌套使用以实现更复杂的条件判断。其语句的格式为:
if (条件1) if(条件2) 执行语句1; else if(条件3) 执行语句3; else 执行语句4;
这里else始终与最近的if语句配对使用,显然这种多分支语句比简单的if-else语句具有更丰富、更复杂的表达能力。
【范例4-3】代码4.3是if-else多分支语句示例程序。
代码4.3 if-else多分支语句示例程序
1 public class IfElseMulTest{ 2 public static void main(String[] args){ 3 //定义3个整数x、y、z,并赋予初值 4 int x=2007; 5 int y=2008; 6 int z=2009; 7 if(x>y) 8 if(x>z) //这里x>y为真,再比较x与z哪个大,判断是否x>z 成立 9 System.out.println("x 最大"); //x>z成立,输出x最大 10 else 11 System.out.println("z 最大"); //否则x<z成立,输出z 最大 12 else 13 if(y>z) //判断是否y>z成立 14 System.out.println("y 最大"); //y>z成立,输出y 最大 15 else 19 System.out.println("z 最大"); //y>z不成立,输出z 最大 20 } 21 }
【运行效果】
z 最大
【代码说明】该段代码的作用是比较3个整数中的最大者,并打印输出。
4.3.3 if嵌套语句
if嵌套语句也是经常使用的多分支判断语句,在一次判断之后又有新一层的判断,接着又有一层判断,逐渐深入,达到实现复杂判断的目的。这种多层次判断相当于多条件判断,在满足几个条件后再执行适当的语句。if嵌套语句的格式是:
if(条件1) if(条件2) if(条件3) 执行语句1;
在条件1成立的条件下继续判断,直到条件3也成立才执行语句1。如果其中有一个条件不满足,则跳出该if嵌套语句,继续执行嵌套语句之外的代码。
4.3.4 switch语句
switch语句是在多条语句中选择其一执行的语句。其语句的格式为:
switch(表达式) case 值1 执行语句1; break; case 值2 执行语句2; break; case 值3 执行语句3; break; default: 执行语句4; break;
对于switch语句,表达式的值只能是下列4种中的一种:char、short、int、byte。一旦计算完表达式的值,程序将依次把该值与“case值n”中的值比较,一旦相等则执行该case后的“执行语句n”,接着跳出switch语句。如果没有匹配的值,则执行默认处理,执行default后的执行语句而后跳出switch语句。如果switch语句中没有default关键字,默认没有匹配值则跳出switch语句。
【范例4-4】代码4.4是switch多分支语句的例子,该例子通过输入的数字判断是星期几,并打印相应的信息。
代码4.4 switch多分支语句示例程序
1 public class SwitchTest{ 2 public static void main(String[] args){ 3 4 int Day=Integer.parseInt(args[0]); //取得用户输入的参数,把该参数转化为整数对象 5 6 switch(Day){ //调用switch语句 8 case 1: //如果Day的值为1,则执行第9行语句 9 System.out.println("星期一"); 10 break; 11 case 2: //如果Day的值为2,则执行第12行语句 12 System.out.println("星期二"); 13 break; 14 case 3: //如果Day的值为3,则执行第15行语句 15 System.out.println("星期三"); 16 break; 17 case 4: //如果Day的值为4,则执行第18行语句 18 System.out.println("星期四"); 19 break; 20 case 5: //如果Day的值为5,则执行第21行语句 21 System.out.println("星期五"); 22 break; 23 case 6: //如果Day的值为6,则执行第24行语句 24 System.out.println("星期六"); 25 break; 26 case 7: //如果Day的值为7,则执行第27行语句 27 System.out.println("星期日"); 28 break; 29 default: //如果Day的值不在1~7之间,则执行第30行语句 30 System.out.println("输入的数字在1-7之间!!!"); 31 break;
【运行效果】代码执行结果如图4.2所示。
图4.2 switch示例程序的执行结果
【代码说明】图4.2中指令java SwitchTest 2的含义是启动Java虚拟机、运行SwitchTest.class文件,该文件是Java虚拟机可以解释的字节码文件。参数2赋予代码4.3中第2行的main(String[] args)方法中的数组的第一个元素,即args[0]=2。
4.3.5 分支语句中的return
在分支语句中可以使用return语句返回一种类型的数据,如boolean型、int型等,但return只能用在方法中,表示该方法返回一个值。当然方法可以没有返回值,即返回值为空(void)。
【范例4-5】代码4.5是分支语句中的return示例程序。
代码4.5 分支语句中的return示例程序
1 private int returnInt(int xx,int yy){ 2 if(xx>yy) 3 return xx; 4 else 5 return yy; 6 }
【代码说明】该方法的作用是比较两个数的大小,并返回较大的那个数。该方法的返回值是整型中的int型。本例只是某个类中的一个方法,不具备运行能力,所以没有运行效果。
4.4 循环语句
循环语句,顾名思义是循环执行的语句,即在满足一定条件的基础上,循环执行循环体中的语句,它是一种反复执行一段程序的流程结构,循环语句包括while循环语句、do-while循环语句和for循环语句。
4.4.1 while循环语句
while循环语句的语句格式为:
while(表达式){ 执行语句; }
当表达式的值为真时,执行“{}”内的语句;当表达式的值为假时,则不执行“{}”内的语句,跳出while循环语句。
【范例4-6】代码4.6是 while循环语句示例程序。在这个例子中依次输入数组中的数值,并打印出来。while条件表达式的作用就是保证在数组的有效长度内,一旦超过数组的长度,while循环终止,程序退出while循环。
代码4.6 while循环语句示例程序
1 public class WhileTest{ 2 public static void main(String[] args){ 3 int intArray[]={20,2,33,34,89,400,30,56}; //定义数组并初始化该数组,数组长度为8 4 int counter=0; //定义一个计数器,while每循环一次,计数器加1 5 while(counter<8){ //执行while循环,在计数器的值小于8时,执行while后的语句 6 System.out.println(intArray[counter]); 7 counter++; 8 } 9 } 10 }
【运行效果】
20 2 33 34 89 400 30 56
图4.3 while循环语句执行流程图
【代码说明】在while语句的条件表达式中,之所以counter<8而不是counter<9是因为数组是从0开始计算,即intArray[0],表示数组的第一个数据。当counter=7时,程序输出的是数组的最后一个数据,而后counter++,counter变为8,再继续while判断,而8<8不成立,程序退出while循环。
while循环语句的执行过程如图4.3所示。
4.4.2 do-while循环语句
do-while循环语句的格式为:
do 执行代码; while(布尔表达式)
执行该循环语句时,首先执行do之后的代码段,再判断while后的布尔表达式。如果布尔表达式的值为真,则继续执行do后的代码段;如果布尔表达式的值为假,则不再执行do后的代码段,程序跳出do-while循环。细心的读者可能会发现,do-while语句至少执行一次do后的代码段;while语句如果其布尔表达式为假,则while后的代码就不可能执行。这是do-while语句与while语句的重要区别。
【范例4-7】代码4.7 是do-while循环语句的示例程序。该例子在计数器的值小于1000时输出计数器的值,而当计数器的值大于或等于1000时,则停止输出。
代码4.7 do-while循环语句示例程序
1 public class DoWhileTest{ 2 public static void main(String[] args){ 3 int counter=0; 4 //首先会执行do语句,再执行while判断 5 do{ 6 System.out.println("当前counter is:"+counter++); 7 } 8 //判断counter的值是否小于1000,如果小于1000则继续执行do语句,则退出do-while循环 9 while(counter<1000) 10 } 11}
【运行效果】
“当前counter is:0”到“当前counter is:999”。
【代码说明】第9行是决定循环多少遍的条件,从0~999,一共循环了1000遍。
4.4.3 for循环语句
图4.4 for循环语句的流程图
for循环语句是Java提供的非常重要的循环语句。其语句格式为:
for(初始表达式;布尔表达式;增量表达式) { 执行代码; }
循环变量的初始值由初始表达式赋予,也可以没有初始表达式。布尔表达式是判断是否继续执行“执行代码”的依据,如果布尔表达式为真则继续执行“执行代码”,如果为假则跳出for循环。增量表达式在“执行代码”运行后计算。一般,增量表达式与for循环的初始值相关。for循环语句的程序流程如图4.4所示。
【范例4-8】代码4.8是for循环语句的示例程序。这个例子在数组中选择大于60的数,并打印这些数据。
代码4.8 for循环语句示例程序
1 public class ForTest{ 2 public static void main(String[] args){ 3 int IntArray[]={29,39,49,80,40,94,102,67}; //声明并定义一个数组 IntArray 4 for(int i=0 ; i<7 ; i++) //执行循环语句 5 if(IntArray[i]>60){ //判断数组中数据IntArray[i]的值是否大于60 6 System.out.println(IntArray[i]); 7 } 8 } 9 }
【运行效果】
80 94 102
【代码说明】这里for循环的执行过程是:初始化一个int型变量i为0,判断布尔表达式的值是否为真,此时0<7,布尔表达式的值为真,执行代码段。接着判断IntArray[0]是否大于60,这里IntArray[0]=29不大于60,退出if语句,执行for循环的增量表达式i++。此时i=1,继续判断布尔表达式,i=1<7成立,继续执行代码段,依次执行下去,直到i<7不成立为止。
4.5 跳转语句
跳转就是指不按语句的正常顺序执行,而是突然改变语句的运行顺序。本节学习Java中常见的两个跳转语句:一个是break跳转语句,该语句的作用是直接跳出循环语句或判断分支语句;另一个是continue跳转语句,该语句的作用是程序从循环体的开始处执行,不必考虑循环体中已经执行了多少轮循环。
4.5.1 break跳转语句
使用跳转语句,可以更直接地控制程序的流程,break跳转语句就是其中之一,其作用是直接跳出循环语句或分支语句如switch语句。在switch分支语句中,一旦执行break跳转语句,程序就退出switch语句。【范例4-9】对代码4.8作相应修改,在第6行代码后,添加跳转语句break,其作用是在获得第一个大于60的数据时输出该值并跳出for循环。这样就实现了获得数组中第一个大于60的数据,当然也获得了该数据在数组中的位置。在for循环外增加一行输出语句“System.out.println("退出for循环");”。
5 if(IntArray[i]>60){ 6 System.out.println(IntArray[i]); 7 break; 8 } 9 ... 10 System.out.println("退出for循环");
图4.5 break跳转语句的执行结果
【运行效果】图4.5是代码4.9修改后的执行结果。
【代码说明】程序首先输出第一个大于60的数“80”,而后执行break语句,跳出for循环。随后执行for循环后的语句,即打印“退出for循环”。
4.5.2 continue跳转语句
continue跳转语句正好与break跳转语句相反,当执行continue语句时,程序从循环体的开始处执行,而不考虑循环体中已经执行了多少轮循环。在for循环语句中,执行到continue语句时,不再执行循环体中其他的代码,而是直接跳转到增量表达式,再开始下一轮的for循环。
在while和do-while语句中,运行到continue语句时则跳转到相应的条件表达式,再开始下一轮的循环。
【范例4-10】代码4.9是continue跳转语句在for循环语句中的示例程序。
代码4.9 continue跳转语句示例程序
1 public class ContinueTest{ 2 public static void main(String[] args){ 3 int i=1; 4 for(; i<5;i++){ 5 System.out.println("i="i); 6 System.out.println("第"+i+"轮循环开始"); 7 if(i>1) 8 continue; 9 System.out.println("第"+i+"轮循环结束"); 10 } 11 } 12 }
【运行效果】程序的运行结果如图4.6所示。
图4.6 continue跳转语句的执行结果
【代码说明】该程序在第3行首先初始化一个整数i,在for循环中,首先输出当前是第几轮循环。如果是第1轮循环则输出“第1轮循环开始”,如果当前的循环次数大于1则执行continue语句,此时程序跳转到for循环语句的增量表达式,继续for循环语句内的代码。因为第1轮循环后,循环次数都大于2,所以不会再执行循环体内的第9行代码。
4.6 常见面试题分析
4.6.1 Java提供了哪几种循环结构,它们各自的特点是什么
Java提供了3种循环结构:for、while和do-while语句。它们各自适用于不同的情况,其中,for循环适合于能确定循环次数的循环结构;while语句则适合单条件的循环;而do-while语句在执行某段代码之后可能再循环的时候更适合一些。
4.6.2 break和continue关键词的掌握
下面代码运行后的打印结果是什么?
public class Test { public static void main(String args[]) { int i=0; outer: while (true) { i++; inter: for (int j=0; j<10; j++) { i+=j; if (j==3) continue inter; break outer; } continue outer; i} iSystem.out.println("i="+i); } }
请选择一个正确的答案。
(a)1
(b)2
(c)3
(d)4
【分析】本面试题中,外层while循环的条件保持为true,因此外层循环体得以执行。i的初始值为0,循环中i++语句使得i的值为1,然后开始执行内层循环。内层循环是for语句,循环变量j的初始值为0,满足j<10,因此内层循环被执行。由于此时j==0,所以i+=j的结果仍然是i=1,而且if后的continue语句不被执行。从而开始执行“break outer;”,导致跳出外层循环,直接执行外循环体后的输出语句。由于此时i=1,所以程序输出结果为1。
4.6.3 for语句的循环条件
编译、运行下面代码的结果是什么?请选择一个正确的答案。
public class Test { static boolean foo(char c) { System.out.print(c); return true; } public static void main(String[] argv) { int i=0; for (foo('A'); foo('B') && (i < 2); foo('C')) { i++; foo('D'); } } }
(a)ABDCBDCB
(b)ABCDABCD
(c)不能编译
(d)编译正确,但是运行时出现错误
【分析】
for循环里面判断的条件要为真,与判断是什么没有关系。就像这里,虽然打印的是字母,但却不是false,所以可以执行。
第一次进行循环:
1)foo('A')打印字母A,(注:这里不是false条件就默认为true条件)。
2)foo('B')打印字母B,i=0,比较(i<2),条件为true,执行循环体,foo('D')打印字母D。
3)foo('C')打印字母C。
第二次循环:
1)foo('B')打印字母B,i=1,比较(i<2)为true,执行循环体,foo('D')打印字母D。
2)foo('C')打印字母C。
第三次循环:foo('B')打印字母B,i=2,比较(i<2)为false,退出循环,得到结果(a)。
4.7 本章习题
1. Java条件语句如何分类?
2.如何使用分支语句、循环语句和跳转语句?
3.阅读程序,判断整数m、n的最后值和含义。
int m=0,n=0; for(int i=0; i<100 ;i++){ if(i%3==0){ m++; } if(i%7==0){ n++; } }
4.编写程序:计算1~100的整数累加和,并显示每个整数和当前累加和的对应关系。
5.计算30的阶乘。
注意:
1)在Java程序流程控制中,最好少使用或不使用跳转语句,因为使用跳转语句往往容易破坏Java程序良好的面向对象特性。
2)在使用嵌套语句时,如果超过3层嵌套要重新考虑该功能的设计,一般嵌套语句不能超过3层。