3.5 选择与循环语句

到目前为止,本书所编写的程序都是简单的程序语句。如果想处理二选一或者多选一的操作,那么判断就是很好的选择;如果想处理重复的工作时,“循环”就是一个很好的选择,它可以运行相同的程序片段,还可以使程序结构化。本章将介绍选择与循环结构语句,还将学习如何利用这些不同的结构编写出有趣的程序,让程序的编写更灵活,操控更方便。

3.5.1 程序的结构

一般来说程序的结构包含3种:顺序结构、选择结构、循环结构。这三种结构有一个共同点,就是它们都只有一个入口,也只有一个出口。这些单一入、出口可以让程序易读、好维护,也可以减少调试的时间。现在以流程图的方式来让读者了解这3种结构的不同。

1.顺序结构

本书前面所讲的那些例子采用的都是顺序结构,程序自上而下逐行执行,一条语句执行完之后继续执行下一条语句,一直到程序的末尾,如图3-10所示。

顺序结构在程序设计中是最常使用到的结构,在程序中扮演了非常重要的角色,大部分的程序基本上都是依照这种由上而下的流程来设计。

2.选择结构

选择结构是根据条件的成立与否决定要执行哪些语句的一种结构,其流程图如图3-11所示。

图3-10 程序的顺序结构流程图

图3-11 程序的选择结构流程图

这种结构可以依据判断条件的结构来决定要执行的语句。当判断条件的值为真时,就运行“语句1”;当判断条件的值为假时,则执行“语句2”。不论执行哪一个语句,最后都会再回到“语句3”继续执行。

【例3.26】验证选择结构

程序执行结果:

上面的程序完成了选择结果,当条件满足的时候会执行if语句中的内容,读者可以自行修改程序中x和y的内容,观察程序的运行结果。

3.循环结构

图3-12 程序循环结构的流程图

循环结构则是根据判断条件的成立与否决定程序段落的执行次数,而这个程序段落就称为循环主体。循环结构的流程图如图3-12所示。

3.5.2 选择结构

选择结构包括if、if…else及switch语句,语句中加上了选择结构之后,就像是十字路口,根据不同的选择,程序的运行会有不同的结果。

1.if语句

前面简单地介绍了if的用法。要根据判断的结构来执行不同的语句时,使用if语句就是一个很好的选择,它会准确地检测判断条件成立与否,再决定是否要执行后面的语句。

【格式3-3 if语句的格式】

若是在if语句主体中要处理的语句只有一个,则可省略左、右大括号。当判断条件的值为真(true)时,就会逐一执行大括号里面所包含的语句,if语句的流程图如图3-13所示。

选择结构中除了if语句之外,还有if…else语句。在if语句中如果判断条件成立,即可执行语句主体内的语句,但若要在判断条件不成立时可以执行其他的语句,使用if…else语句可以节省判断的时间。

2.if…else语句

当程序中存在含有分支的判断语句时,就可以用if…else语句处理。当判断条件成立,即执行if语句主体;判断条件不成立时,则会执行else后面的语句主体。if…else语句的格式如下:

【格式3-4 if…else语句的格式】

若是在if语句或else语句主体中要处理的语句只有一个,可以将左、右大括号省去。if…else语句的流程图如图3-14所示。

【例3.27】通过if…else语句判断一个数字是奇数还是偶数

程序执行结果:

上面的程序是通过取模的方式判断是奇数还是偶数,如果一个数字除以2余数为0,则肯定是偶数,相反一定是奇数。

图3-13 if语句的流程图

图3-14 if…else语句的基本流程

3.三目运算符

有一种运算符可以代替if…else进行变量赋值的语句,即三目运算符,如表3-17所示。

表3-17 三目运算符

使用三目运算符时,操作数有3个,其格式如下:

【格式3-5 三目运算符语句的格式】

将上面的格式以if语句解释,就是当条件成立时执行表达式1,否则执行表达式2,通常会将这两个表达式之一的运算结果指定给某个变量,也就相当于下面的if…else语句。

【格式3-6 ?:与if…else语句的相对关系】

【例3.28】使用三目运算符求出两个数字中的最大值

程序执行结果:

可见,使用条件运算符编写程序时较为简洁,它用一个语句就可以替代一长串的if…else语句,所以三目运算符的执行速度也较高。

4.if…else if…else语句

如果需要在if…else里判断多个条件时,就需要if…else if…else语句了,其格式如下:

【格式3-7 if…else if…else语句】

这种方式用在含有多个判断条件的程序中,如下面的范例所示。

【例3.29】使用if…else if…else语句

程序执行结果:

5.switch语句

switch语句可以将多选一的情况简化,而使程序简洁易懂,本节将介绍如何使用switch语句及break语句;此外,也要讨论在switch语句中如果不使用break语句会出现的问题。下面将介绍switch语句该如何使用。

要在许多的选择条件中找到并执行其中一个符合判断条件的语句时,除了可以使用if…else不断地判断外,还可以使用另一种更方便的方式,即多重选择—switch语句。使用嵌套if…else语句最常发生的状况就是容易将if与else配对混淆,从而造成阅读及运行上的错误。使用switch语句则可以避免这种错误的发生。switch语句的格式如下:

【格式3-8 switch语句】

要特别注意的是,switch语句中的选择值只能是字符或是常量。

提示

switch支持的新数据类型。

在JDK 1.5之后,switch中也支持枚举类的判断,对于枚举的讲解将在本书的第3部分为读者介绍。同时从JDK 1.7开始,switch语句也支持String型数据的判断。

看看switch语句执行的流程:

(1)switch语句先计算括号中表达式的结果,结果是数字、字符或是枚举。

(2)根据表达式的值检测是否符合执行case后面的选择值,若是所有case的选择值皆不符合,则执行default所包含的语句,执行完毕即离开switch语句。

(3)如果某个case的选择值符合表达式的结果,就会执行该case所包含的语句,一直遇到break语句后才离开switch语句。

图3-15 switch语句的流程图

(4)若是没有在case语句结尾处加上break语句,则会一直执行到switch语句的尾端才会离开switch语句。break语句在下面的章节中会介绍到,读者只要先记住break是跳出语句即可。

(5)若是没有定义default执行语句,则什么也不会执行,直接离开switch语句。

根据上面的描述,可以绘制出如图3-15所示的switch语句流程图:

【例3.30】以下程序验证了switch语句的作用

程序执行结果:

读者可以自行将oper中的操作修改为“+”“-”“*”“/”等,如果设置的是一个未知的操作,程序将提示“未知的操作!”

提示

break语句的作用。

从以上的程序,读者可以发现,在每一个case语句之后都加上了一个break语句,如果不加入此语句的话,则switch语句会从第一个满足条件的case开始依次执行操作,如下面测试代码:

从上面程序的运行结果可以发现,程序在第1个条件满足后,由于没有设置相应的break语句,则从第1个满足条件开始就依次向下继续执行了。

从JDK 1.7开始switch语句的功能得到了加强,可以直接利用String进行数据的判断。

【例3.31】在switch语句中使用String

程序执行结果:

上面的程序实现了字符串数据的判断,但是在判断的过程之中是会区分字符串大小写的。

3.5.3 循环结构

循环结构指的是某一段代码可以实现重复的执行,在Java中支持while循环和for循环两类循环。

1.while循环

while是循环语句,也是条件判断语句。当事先不知道循环该执行多少次时,就要用到while循环。while循环的格式如下:

【格式3-9 while循环语句】

当while循环主体有且只有一个语句时,可以将大括号省去。在while循环语句中,只有一个判断条件,它可以是任何表达式,当判断条件的值为真,循环就会执行一次,再重复测试判断条件,执行循环主体,直到判断条件的值为假,才会跳离while循环。下面列出了while循环执行的流程:

(1)第1次进入while循环前,就必须先为循环控制变量(或表达式)赋起始值。

图3-16 while循环流程图

(2)根据判断条件的内容决定是否要继续执行循环,如果条件判断值为真(true),继续执行循环主体;条件判断值为假(false),则跳出循环执行其他语句。

(3)执行完循环主体内的语句后,重新为循环控制变量(或表达式)赋值(增加或减少),由于while循环不会自动更改循环控制变量(或表达式)的内容,所以在while循环中为循环控制变量赋值的工作要由设计者自己来做,完成后再回到步骤(2)重新判断是否继续执行循环。

根据上述程序流程,可以绘制出如图3-16所示的while循环流程图:

【例3.32】使用while循环进行累加操作

程序执行结果:

从上面的程序中可以发现,在while语句执行前先进行循环条件的判断(x<=10),在while语句之后对循环条件进行修改(x++),如果程序中没有修改循环条件的话,那么程序将出现“死循环”的情况。

注意

避免死循环。

造成死循环的原因就是循环条件一直都满足,所以循环体一直都会被执行。如果代码在开发中不幸出现死循环,在命令行方式下,可以按“Ctrl+C”快捷键结束程序的执行。

2.do…while循环

do…while循环也是用于未知循环执行次数的情况,而while循环及do…while循环最大不同就是进入while循环前,while语句会先测试判断条件的真假,再决定是否执行循环主体,而do…while循环则是先执行一次循环主体,然后再测试判断条件的真假,所以无论循环成立的条件是什么,使用do…while循环时,至少都会执行一次循环主体。do…while循环的格式如下:

【格式3-10 do…while循环语句】

当循环主体只有一个语句时,可以将左、右大括号去除。第一次进入do…while循环语句时,不管判断条件(它可以是任何表达式)是否符合执行循环的条件,都会直接执行循环主体。循环主体执行完毕,才开始测试判断条件的值,如果判断条件的值为真,则再次执行循环主体,如此重复测试判断条件,执行循环主体,直到判断条件的值为假,才会跳离do…while循环。下面列出了do…while循环执行的流程:

(1)进入do…whle循环前,要先为循环控制变量(或表达式)赋起始值。

图3-17 do…while循环流程图

(2)直接执行循环主体,循环主体执行完毕,才开始根据判断条件的内容决定是否继续执行循环,条件判断值为真(true)时,继续执行循环主体;条件判断值为假(false)时,则跳出循环,执行其他语句。

(3)执行完循环主体内的语句后,重新为循环控制变量(或表达式)赋值(增加或减少),由于do…while循环和while循环一样,不会自动更改循环控制变量(或表达式)的内容,所以在do…while循环中赋值循环控制变量的工作要由自己来做,再回到步骤(2)重新判断是否继续执行循环。

根据上述的描述,可以绘制出如图3-17所示的do…while循环流程图。

【例3.33】使用do…while循环完成之前的累加操作

程序执行结果:

从上面程序的运行结果可以发现while和do…while的操作结果是一样的。但是do…while与while循环不同的是do…while操作中就算条件不满足,也会至少执行一次。而while如果条件不满足,则一次也不会被执行。

3.for循环

对于while和do…while两种循环来讲,操作时并不一定非要明确的知道循环的次数,而如果开发者已经明确的知道了循环次数的话,那么就可以使用另外一种循环语句—for循环。

【格式3-11 for循环语句】

若是在循环主体中要处理的语句只有一个,可以将“{}”省去。下面列出了for循环的流程:

(1)第一次进入for循环时,为循环控制变量赋起始值。

(2)根据判断条件的内容检查是否要继续执行循环,当判断条件值为真(true)时,继续执行循环主体内的语句;判断条件值为假(false)时,则会跳出循环,执行其他语句。

(3)执行完循环主体内的语句后,循环控制变量会根据增减量的要求,更改循环控制变量的值,再回到步骤(2)重新判断是否继续执行循环。

根据上述描述,可以绘制出如图3-18所示的for循环流程图。

图3-18 for循环流程图

说明

提问:用哪种循环好?

本书给出了3种循环的操作,那么在实际工作中,如何去选择这些使用的循环?

回答:主要使用while和for循环。

就笔者的经验来讲,在开发之中,while和for循环的使用次数较多,而这两种的使用环境如下:

(1)while循环:在不确定循环次数,但是确定循环结束条件的情况下使用;

(2)for循环:确定循环次数的情况下使用。

【例3.34】使用for循环完成累加操作

程序执行结果:

4.循环的嵌套

多个循环语句是可以嵌套操作的,例如:如果现在要打印一个九九乘法表,则肯定要使用两层循环完成。

【例3.35】打印九九乘法表

程序执行结果;

程序说明:

(1)i为外层循环的循环控制变量,j为内层循环的循环控制变量。

(2)当i为1时,符合外层for循环的判断条件(i<=9),进入另一个内层for循环主体,由于是第1次进入内层循环,所以j的初值为1,符合内层for循环的判断条件(j<=i),进入循环主体,输出i*j的值(1*1=1),如果最后j的值仍符合内层for循环的判断条件(j<=i),再次执行计算与输出的工作,直到j的值大于i时,离开内层for循环,回到外层循环。此时,i会加1成为2,符合外层for循环的判断条件,继续执行内层for循环主体,直到i的值大于9时即离开嵌套循环。

3.5.4 循环的中断

在Java语言中,可以使用如break、continue等中断语句,站在结构化程序设计的角度上,并不鼓励用户使用,因为这些中断语句会增加调试及阅读的困难。在本节中将为读者介绍break及continue语句。

1.break语句

break语句可以强迫程序中断循环,当程序执行到break语句时,即会离开循环,继续执行循环外的下一个语句,如果break语句出现在嵌套循环中的内层循环,则break语句只会跳出当前层的循环。以下面的for循环为例,在循环主体中有break语句时,当程序执行到break,会离开循环主体,而继续执行循环外层的语句。

【格式3-12 break语句格式】

下面的程序是利用for循环输出循环变量i的值,当i除以3所取的余数为0时,使用break语句的跳离循环,并于程序结束前输出循环变量i的结果。

【例3.36】使用break

程序执行结果:

从上面程序运行结果中可以发现,当i的值为3时,判断语句满足,则执行break语句退出整个循环。

2.continue语句

continue语句可以强迫程序跳到循环的起始处,当程序运行到continue语句时,即会停止运行剩余的循环主体,而是回到循环的开始处继续运行。以下面的for循环为例,在循环主体中有continue语句,当程序执行到continue,即会回到循环的起点,继续执行循环主体的部分语句。

【格式3-13 continue语句格式】

【例3.37】将之前for循环程序修改为continue循环,观察运行结果

程序执行结果:

从上面的程序运行结果中可以发现,当i的值为3时,程序并没有向下执行输出语句,而是退回到了循环判断处继续向下执行,所以continue只是中断了一次的循环操作。

提示

局部变量。

另外,需要提醒读者的是,在循环语句中定义的变量属于局部变量,所谓的局部变量是指此变量只能在循环语句中使用,而循环语句之外无法使用。

范例:如以下代码所示