第4章 流程控制
(视频讲解:1小时26分钟)
流程控制对于任何一门编程语言来说都至关重要,它提供了控制程序步骤的基本手段。如果没有流程控制语句,整个程序将按照线性的顺序来执行,不能根据用户的输入决定执行的序列。本堂课将向读者介绍Java语言中的流程控制语句。
学习摘要:
Java语言的复合语句
if条件语句
switch多条件分支语句
if语句的灵活运用
while循环语句的使用
do…while循环语句的使用
while与do…while语句的区别
for循环语句的使用
4.1 复合语句
在前面的学习当中已经接触到了复合语句(也称为代码块)。它使用大括号“{}”把多条语句括起来,作为一条复合语句。大括号内可以是一条语句和多条语句,甚至没有语句都可以。而且在任何可以使用单一语句的地方都可以使用复合语句。并且在复合语句中还可以嵌套复合语句。
和C语言或其他语言相同,Java语言的复合语句是以整个块区为单位的语句,所以又称块语句。复合语句由开括号“{”开始,闭括号“}”结束。
【例4.1】 在主方法中定义复合语句块其中包含另一复合语句块,代码如下。(实例位置:资源包\源码\04\4.01)
运行结果如图4.1所示。
图4.1 实例的运行结果
在使用复合语句时要注意。复合语句中定义的变量是局部变量,复合语句就是该变量的作用域。在该作用域中某个变量被创建并能够被使用。如果在作用域外使用该变量,就会发生错误。例如在本实例中如果在复合语句外使用变量z、y、b将会出现错误。而变量x可在整个方法体中使用。
4.2 条件语句
视频讲解
条件语句可根据不同的判断条件执行不同的语句,判断条件就是关系表达式,例如:age>30,要求30岁以上的用户。条件语句包括if条件语句与switch多分支语句。本节将向读者介绍这两种条件语句的用法。
4.2.1 IF条件判断语句
if条件语句是一个重要的编程语句,它告诉程序在某个条件成立的情况下,执行某段程序,如果条件不成立,就执行另外的语句,这里说的语句通常为复合语句。if条件语句可分为:简单的if条件语句、if…else语句和if…else if多分支语句。
1.简单的if条件语句
使用简单的if条件语句,可判断是否执行紧跟在条件之后的复合语句。关键字if之后是作为条件判断的“关系表达式”,如果该表达式返回的结果为true,则执行其后的语句;若为false,则不执行if条件以后的语句,语法如下。
关系表达式:必要参数。它最后返回的结果必须是一个布尔值,它可以是一个单纯的布尔变量与常量、或者是逻辑运算符的表达式。
复合语句:可选参数,当关系表达式的值为true时执行语句。如“复合语句”中仅有一条语句,则可以使用单一语句。例如:
说明
虽然if和else语句后面的复合语句块只有一条语句,省略“{ }”改用单一语句并无语法错误,但为了增强程序的可读性最好使用带“{ }”的复合语句。
如果条件语句后的复合语句省略时,需要在if语句末尾添加分号“;”,这时候if语句不做任何操作。
例如:省略了if语句中的复合语句。
if (387 > 322 && 10 != 10);
另外,还可以使用空的复合语句。例如:
if (387 > 322 && 10 != 10){ }
简单的if条件语句的执行过程如图4.2所示。
图4.2 简单if条件语句的执行过程
下面以实例说明简单if语句的执行过程。
【例4.2】 如果商品单价低于50,就购买该商品,代码如下。(实例位置:资源包\源码\04\4.02)
运行结果如图4.3所示。
图4.3 实例运行结果
如果把实例中的变量price的值改为110.50,那么程序就不会输出“购买该商品”字符串,而直接输出“选购完毕”字符串。
2.if…else语句
if…else语句是条件语句中最常用的一种形式,它会针对某种条件有选择地做出处理。通常表现为“如果满足某种条件,就进行某种处理,否则就进行另一种处理”,语法如下。
if后面()内的表达式的值必须是boolean型的。如果表达式的值为true,则执行if语句后的复合语句1;如果表达式的值为false,则执行else后面的复合语句2。if…else语句的执行过程如图4.4所示。
图4.4 if…else语句的执行过程
当复合语句省略时,代码格式与简单的if语句规定相同。下面以实例说明if…else语句的应用。
【例4.3】 根据商品单价,判断是否购买,代码如下。(实例位置:资源包\源码\04\4.03)
运行结果如图4.5所示。
图4.5 实例运行结果
技巧
对于if…else语句可以使用三元运算符对语句进行简化。如下面代码:
if(a > 0) b = a; else b = -a;
可以简写成:
b = a > 0?a:-a;
上段代码为求绝对值的语句,如果a > 0,就把a的值赋值给变量b,否则将-a赋值给变量b。使用三元运算符的好处是可以简洁代码,并且有一个返回值。
3.if…else if多分支语句
if…else if多分支语句用于针对某一事件的多种情况进行处理。通常表现为“如果满足某种条件,就进行某种处理,否则如果满足另一种则执行另一种处理”,语法如下。
条件表达式1至条件表达式n:必要参数。可以由多个表达式组成,但最后返回的结果一定要为boolean类型。
复合语句:当条件表达式1的值为true时,执行复合语句1,当条件表达式2的值为true时,执行复合语句2,依次类推。if…else if多分支语句的执行过程如图4.6所示。
图4.6 if…else if多分支语句流程图
【例4.4】 根据商品价格以及是否打折,做出多种判断,代码如下。(实例位置:资源包\源码\04\4.04)
运行结果如图4.7所示。
图4.7 实例运行结果
4.2.2 IF语句的嵌套
if语句除了多分枝判断格式外,还可以嵌套使用。从本堂课之前的讲解,读者应该明白if条件判断语句执行的都是复合语句,笔者建议这样做,复合语句使用大括号“{ }”定义多条语句,那么也可以在其中再插入新的if语句,这样就形成了if语句的嵌套,语法如下。
其中使用条件表达式2的if语句嵌套在使用条件表达式1的if语句中,if语句的嵌套使用可以实现更加复杂的逻辑判断。它很接近我们的思维方式。
【例4.5】 根据商品价格以及是否打折,打折多少做出多种判断,代码如下。(实例位置:资源包\源码\04\4.05)
运行结果如图4.8所示。
图4.8 实例运行结果
4.2.3 switch分支语句
if语句和它的嵌套使用虽然能够处理复杂的多路分支判断,实现程序流程的控制,但是使用起来不太方便,编写的代码可读性不高。如果程序需要的只是使用分支语句根据不同的变量值执行不同的操作,那么,Java提供的switch语句能够解决上述问题,它更加适合这种应用,而且可读性非常好。
switch语句根据一个表达式的结果,执行特定的操作,语法如下。
表达式:这是必要的参数,它的结果用于判断执行的case子句。
case常量:必要的参数,它是分支的入口,用于执行特定于常量的操作。
语句:可以是多条语句,但不是复合语句,因为不需要使用大括号“{ }”,它是分支的业务处理代码。
break:可选参数,一般放在case分支语句的最后,在完成操作后,用于跳出switch语句,继续执行程序的其他流程。
default:这是可选参数,它是switch语句的默认分支入口,如果表达式的值和所有case子句的常量都不匹配,那么将执行default分支下的语句。
switch分支语句的流程如图4.9所示。
图4.9 switch语句流程图
switch语句要点如下。
语句中表达式类型的级别必须低于int整数类型,即表达式的值只能是byte、short、char、int类型,不能使用浮点类型或long长整型。
case子句中的常量必须和表达式的类型兼容,而且每个case子句的常量值都不能相同。
switch语句首先计算表达式的值,如果表达式的值和某个case后面的变量值相同,则执行该case语句后的若干个语句直到遇到break语句为止。
如果case语句中没有break语句,将继续执行下一个的case里的语句,直到遇到break语句为止。
若没有一个case子句的常量与表达式的值相同,则执行default分支的语句。default语句为可选的,如果它不存在,而且switch语句中的表达式的值不与任何case的常量值相同,switch则不做任何的处理。
break语句用来跳出switch语句;也可以说结束switch语句,因为case子句只是不同分支的标识,用来匹配表达式的值,是分支的入口。当case与表达式匹配之后,就开始执行分支的语句,而不再比较之后的任何case子句的常量。所以,每个case分支的最后,需要使用break语句来中断switch语句,防止继续执行其他的case分支语句或者default语句。
switch语句的所有功能都可以使用if…else语句实现。switch语句比if…else语句要简练;但是更加复杂的条件分支和单独的条件判断还是要依赖if语句去实现。
如果多个相连的case分支省略break语句可以实现多个条件执行同一业务处理的效果。例如:
当表达式的值是20、30、31中的任何一个,都会执行“System.out.println("我喜欢这个数字");”语句。
【例4.6】 判断顾客对商品折扣的反应情况,分别定义折扣为1至2折、3至4折、5至6折、7至8折,和其他折扣时的输出内容,代码如下。(实例位置:资源包\源码\04\4.06)
运行结果如图4.10所示。
图4.10 实例运行结果
注意
case常量表达式的值可以是字符,但一定不可以是字符串,注意" "和' '的区别。例如,下面的代码是非法的。
【例4.7】 使用switch语句判断指定月份属于一年中的哪个季度。如果是12月、1月、2月,就属于冬季;如果是3月、4月、5月,就属于春季;如果是6月、7月、8月,就属于夏季;如果是9月、10月和11月,就属于秋季。再出现其他数值就输出错误信息,代码如下。(实例位置:资源包\源码\04\4.07)
运行结果如图4.11所示。
图4.11 实例运行结果
4.2.4 if语句和switch语句的区别
if语句和switch语句可以从使用的效率上来进行区别,也可以从实用性的角度来区分。如果从使用的效率上进行区分,在对同一个变量的不同值作条件判断时,使用switch语句的效率相对更高一些,尤其是判断的分支越多越明显。
如果从语句的实用性的角度去区分,那switch语句肯定不如if条件语句。if条件语句是应用最广泛和最实用的语句。
技巧
在程序开发的过程中,具体如何来使用if和switch语句根据实际的情况而定,尽量做到物尽其用,不要因为switch语句的效率高就一味地使用,也不要因为if语句常用就不应用switch语句。要根据实际的情况,具体问题具体分析,使用最适合的条件语句。
4.3 循环控制
视频讲解
循环语句就是在满足一定条件的情况下反复执行某一个操作。在Java中提供了3种常用的循环语句,分别是:while循环语句、do…while循环语句和for循环语句。下面分别对这3种循环语句进行介绍。
4.3.1 for循环
for循环是Java程序设计中最有用的循环语句之一。一个for循环可以用来重复执行复合语句,直到循环条件成立而终止循环体。下面将对for循环做详细的介绍,语法如下。
表达式1:该表达式用于初始化循环控制变量,它只在循环开始时执行一次。
表达式2:循环条件表达式,它的类型为boolean,如果表达式的值为true就执行一次循环体。
表达式3:该表达式用于改变循环体变量的值。
for循环语句的流程如图4.12所示。
图4.12 for循环的流程图
for循环的执行过程如下。
第一步:执行表达式1,完成某一变量的初始化工作;例如int i = 0。
第二步:判断表达式2的值;例如i <= 100。若表达式2的值为true,则执行一次循环体;然后执行第三步,否则退出循环体结束for循环。
第三步:执行表达式3,这部分通常执行循环控制变量的修改。
第四步:跳转到第二步继续执行循环。
【例4.8】 使用for循环来计算100以内(包括100),所有偶数之和,代码如下。(实例位置:资源包\源码\04\4.08)
运行结果如图4.13所示。
图4.13 实例运行结果
【例4.9】 使用for循环输出14和98的所有公约数,代码如下。(实例位置:资源包\源码\04\4.09)
运行结果如图4.14所示。
图4.14 实例运行结果
技巧
在编程时,有时会遇到使用for循环的特殊语法格式来实现无限循环,语法格式如下。
for(;;){ 循环体 }
对于这种无限循环可以通过break语句跳出循环,例如:
for(;;){ if(x < 20) break; x++; }
4.3.2 while循环
while语句是“当型”循环语句,也就是当条件表达式成立时,执行循环体中的内容,其语法格式如下。
条件表达式:这是用于控制循环的条件。例如count <= 100。
循环体:这是条件表达式成立的情况下,执行的程序代码。
while循环语句的流程,如图4.15所示。
图4.15 while语句的执行过程
当条件表达式的返回值为真时,则执行循环体中的语句,当执行完循环体中的语句后,重新判断条件表达式的返回值,直到表达式返回的结果为假时,退出循环。
【例4.10】 通过while循环将整数1到100相加,并将结果输出,代码如下。(实例位置:资源包\源码\04\4.10)
实例中while循环体中的“sum += x++;”语句等价于“sum = sum+x;”和“x = x+1;”两条语句,运行的结果如图4.16所示。
图4.16 实例运行结果
【例4.11】 使用while循环求出100以内所有奇数的和,代码如下。(实例位置:资源包\源码\04\4.11)
运行的结果如图4.17所示。
图4.17 实例运行结果
注意
初学者经常犯的一个错误就是在while表达式的括号后加“;”,如:
这时程序会认为要执行一条空语句,而进入无限循环。Java编译器又不会报错。可能会浪费很多时间去调试,另外该情况同样有可能发生在其他控制语句中,例如for语句和if语句。在程序开发时一定要留意这个问题。
4.3.3 do…while循环
do…while循环语句与while循环语句类似。它们之间的差别是while语句为先判断条件是否成立再执行循环体,而do…while循环语句则先执行一次循环后,再判断条件是否成立。也就是说do…while循环语句中大括号中的程序段至少要被执行一次,语法如下。
与while语句的一个明显的区别是,do…while语句在结尾处多了一个分号(;)。根据do…while循环语句的语法特点总结出do…while循环语句的执行流程,如图4.18所示。
图4.18 do…while循环语句的执行过程
do…while语句的执行步骤如下。
第一步:执行循环体中的语句。
第二步:判断条件表达式的值;如果该值为true,就跳转到第一步。否则退出循环体,继续执行程序的其他代码。
【例4.12】 使用do…while循环求100以内所有奇数的和,代码如下。(实例位置:资源包\源码\04\4.12)
运行结果如图4.19所示。
图4.19 实例运行结果
【例4.13】 分别使用while和do…while语句定义循环,在num变量小于50的情况下输出循环语句名称,num变量的初值为50或大于50的整数。请读者根据本实例牢记两个循环的区别,代码如下。
(实例位置:资源包\源码\04\4.13)
运行结果如图4.20所示。
图4.20 实例运行结果
实例的while循环首先判断条件表达式,当表达式的结果为false时不会执行循环体。而do…while循环会先执行一边循环体,然后判断条件表达式,所以无论num2变量是多少,do…while循环都会输出信息。
4.3.4 print与println方法
在本节之前的所有实例中,都是使用System.out.println()方法输出字符串到控制台的,println()方法在输出字符串时,自动在字符串的末尾添加“\n”换行字符,所以使用该方法输出的字符串和下一次调用该方法输出的内容不会在同一行。
print()方法同样用于输出字符串到控制台,该方法输出字符串后不会自动换行,即多次调用该方法输出的字符串永远不会换行,它们会输出在一行里。除非在字符串中添加“\n”或“\r”字符。而println()方法在输出字符串后,自动添加一个换行符,这是两个方法的区别。例如:
上述代码在控制台只输出一行字符串:“Java编程词典的网站是:www.bccd.com”,而不是多行文本。我们将在下一节嵌套循环中多次组合使用这两个方法。
4.3.5 循环嵌套
在一个循环语句的循环体中,又包含另外一个完整的循环语句,称为嵌套循环。3种不同的循环语句之间可以相互嵌套,嵌套循环可以是多层的,即被嵌套的循环语句还可以再嵌套其他循环,形成3层循环或多层循环。但是笔者不建议使用超过3层的嵌套循环,因为将会使程序更加难以阅读和理解。
【例4.14】 使用双层的for循环在控制台中输出格式化的九九乘法表,要使用“\t”制表符使输出更加工整,代码如下。(实例位置:资源包\源码\04\4.14)
这个实例使用了两层for循环,第一层for循环控制行数,变量i在控制循环的同时也用作乘法表的被乘数。第二层循环控制乘法表的列,循环条件是循环控制变量j小于等于第一层循环控制变量i,这样乘法表的列数就受到限制,形成了梯形表格,运行结果如图4.21所示。
图4.21 实例运行结果
【例4.15】 在控制台中输出金字塔,该金字塔是由左右对称的数字组成,代码如下。(实例位置:资源包\源码\04\4.15)
实例中使用了两层for循环,第一层for循环控制金字塔的行,第二层由3个for循环分别控制每行的前导空格和金字塔的左右两半部分的输出。其中第一个内嵌for循环的控制变量使用倒序方式循环,并在循环体中输出空格字符,这样行数越小,输出的空格字符越多,就像金字塔层数越高面积就越小,直到顶层形成了塔尖。第二个内嵌for循环输出每行的左半部分数字,它也使用倒序的循环控制,由左至右输出从大到小的数字,其中“i < 10 ? " " + i : " " + i”语句使用三元运算符把小于10的数字左侧补两个空格,大于10的数字补1个空格,这样使输出结果更加工整一些。第三个内嵌的for循环以类似的方式在每行的右半部输出从小到大排序的数字,运行结果如图4.22所示。
图4.22 实例运行结果
4.4 循环的跳转
视频讲解
使用循环就像是工厂的流水线作业,可以循环生成商品,提高效率。程序使用循环的目的也是为了提高效率和代码可读性,但是程序开发需要更复杂的业务流程,一个工作很好的循环体,在某些条件下可能需要终止循环,或者在某些条件下需要放弃本次循环。Java语言定义的break语句和continue语句用于循环的跳转,它们可以实现上述功能。
4.4.1 continue跳转语句
continue语句只能应用在for、while和do…while循环语句中,用于结束本次循环直接跳过循环体剩余的语句,进行下一次循环。
语法:continue标号;
参数:标号是可选参数,标号有合法标识符和“:”字符组成,例如“for1:”。
continue语句有两种使用情况。
不带标号跳转
如果执行不带标号的continue语句,将结束本次循环,跳过循环体中剩余的没有被执行的语句,根据循环的条件判断去执行下一次循环,或者结束循环。如果是for循环还要先执行表达式3,改变循环控制变量的值。
【例4.16】 实现输出100以内能被7整除的所有数,使用continue语句过滤其他的数字,代码如下。(实例位置:资源包\源码\04\4.16)
实例中在for循环中加入了if判断语句,如果循环控制变量i不能被7整除,就执行continue语句放弃本次循环;否则输出变量i,这时变量i肯定能被7整除,运行结果如图4.23所示。
图4.23 实例运行结果
带标号跳转
这种情况下,continue语句不是跳过当前循环语句的一次循环,而是跳过标号指定的循环语句的一次循环,然后判断指定标号的循环条件,以决定是否执行标号指定的循环。
标号定义在语句之前,由一个合法的标识符和“:”字符组成,语法如下。
标号:程序代码
continue语句跳转的标号用于指定循环语句,所以定义在循环语句之前。带标号的continue跳转语句经常用在多层循环中。
【例4.17】 使用带标号的for循环和带标号的continue语句输出九九乘法表,代码如下。(实例位置:资源包\源码\04\4.17)
实例中在内层for循环中加入了if判断语句,如果循环控制变量j大于外层循环控制变量i,则这个数字对于乘法表的当前行就无用,所以输出一个空行并执行continue语句跳出到outer标识的for循环,这时内层循环语句就被结束或者说已终止,转去执行outer标识的外层循环,运行结果如图4.24所示。
图4.24 实例运行结果
如果把内层循环的if语句注释掉,如下所示。
然后再运行程序,将会输出如图4.25所示的结果。
图4.25 实例注释if语句后的运行结果
4.4.2 break跳转语句
正常来说,退出循环的方式应该由循环条件来判断和控制,而break语句可以应用在for、while和do…while循环语句中,来实现强行退出循环。这也给循环增加了一些灵活性,即在循环条件为true的情况下,也可以根据需要使用break语句强行退出循环。
语法:break标号;
和continue语句一样,break语句也有两种使用情况。
不带标号
不带标号的break语句可以终止break语句所在的循环。
【例4.18】 使用while循环和break语句输出1至100整数的和,代码如下。(实例位置:资源包\源码\04\4.18)
实例中使用无限循环的while循环不停地累加整数的总和,并使control变量自增,当控制变量大于100的时候,说明100已经被累加到sum总和变量中,这时循环的任务已经完成,应该输出总和变量的数值,并执行break语句退出循环,运行结果如图4.26所示。
图4.26 实例运行结果
带标号
带标号的break语句可以终止标号指定的循环,它常用于跳出多层循环的情况。
【例4.19】 当九九乘法表的积大于16时终止外层循环,代码如下。(实例位置:资源包\源码\04\4.19)
运行结果如图4.27所示。
图4.27 实例运行结果
说明
break语句和continue语句的区别在于:break语句将终止整个循环语句,而continue语句只结束本次循环。
4.5 实战
视频讲解
4.5.1 遍历21世纪的闰年
创建SearchLeapYear类,在该类的主方法中定义一个年历21世纪所有年份的循环,在循环中判断这些年份是否为闰年,并在控制台中把所有闰年年份输出,每行只输出5个闰年,运行结果如图4.28所示。(实例位置:资源包\源码\04\实战\01)
图4.28 实例运行结果
4.5.2 输出空心的菱形
创建Diamond类,在该类的主方法中完成10行的空心菱形输出,实现方法是使用两个双层for循环分别输出菱形的上半部分与下半部分,运行结果如图4.29所示。(实例位置:资源包\源码\04\实战\02)
图4.29 实例输出结果
4.5.3 把用户输入的字母变成大写
编程接收用户输入的小写字母,然后把该字母的编码值减去32,使之变为大写字母。在由小写字母到大写字母的转换过程中,要判断用户输入的内容是否为小写字母,对于其他字符不做任何处理,输出提示信息即可,运行结果如图4.30所示。(实例位置:资源包\源码\04\实战\03)
4.5.4 应用switch语句实现生肖查询
编程接收用户输入的年份数字,输入内容必须是整数,然后通过该数字与12求余数的结果判断生肖,并把判断结果输出到控制台,实例运行结果如图4.31所示。(实例位置:资源包\源码\04\实战\04)
图4.30 实例运行结果
图4.31 实例运行结果
4.5.5 验证用户登录信息
大多系统登录模块都会接收用户通过键盘输入的登录信息,这些登录信息将会被登录模块验证,如果使用的是指定的用户名与密码,则允许程序登录。否则将用户拒之门外。本实例通过if…else进行多条件判断实现了登录信息验证,程序运行结果如图4.32所示。(实例位置:资源包\源码\04\实战\05)
图4.32 输入合法登录信息的效果