《Java语言导学(原书第6版)》一3.4 控制流语句

3.4 控制流语句

源文件中的语句通常按照出现的先后次序自顶向下执行。控制流语句打破了这种常规,它通过决策、循环和分支等,使程序可以有条件地执行特定的代码块。本节介绍Java程序语言支持的决策语句(if-then、if-then-else、switch)、循环语句(for、while、do-while)和分支语句(break、continue、return)。

3.4.1 if-then语句和if-then-else语句

1.if-then语句
if-then语句是最基本的控制流语句。该语句使得当某个条件为真时,程序只执行特定的代码段。再以自行车为例来说明。自行车只有在运动时,Bicycle类才可以使用刹车减速。如下为applyBrakes方法的一种实现:

当条件为假时(也就是说自行车不再运动),就直接跳出if-then语句。
另外,如果then子句只包含一条语句,那么一对花括号可以省略:

何时省略花括号取决于编程人员个人的喜好。但是,省略花括号会降低代码的健壮性。省略花括号后经常会犯一个错误,那就是在then子句中添加第二条语句时忘记添加必需的花括号。编译器不会捕获该类错误,但程序的运行结果是错的。
2.if-then-else语句
if-then-else语句在条件为假时提供第二条执行路径。在applyBrakes方法中使用if-then-else语句执行某个动作,表示在自行车不处于运动状态时使用刹车产生的动作。在这个例子中,该动作就是输出错误消息语句:

下面程序中,IfElseDemo根据testscore的值对成绩定级:90分及以上为A,80分及以上为B,以此类推。

程序输出如下:

注意,testscore的值可能同时满足复合语句“76 >= 70”和“76 >= 60”中的多个表达式。但是,条件一旦满足,就执行相应的语句(grade='C';)而且不会计算后续条件。

3.4.2 switch语句

与if-then和if-then-else语句不同,switch语句可以包含多条可能的执行路径。switch语句通常与byte、short、char、int等基本数据类型一起使用,也会与枚举类型(见第4章)、String类和由某些基本数据类型组成的特殊类(Character、Byte、Short和Integer等,见第9章)一起使用。
下述SwitchDemo程序声明int类型的变量month,其值表示月份。它根据month的值使用switch语句显示月份的名称。

其输出结果为August。
switch语句的主体叫switch块。switch块中的语句可以用一个或多个case标签或default标签来标记。switch语句计算其表达式,并执行匹配的case标签后的所有语句。
该程序的功能也可以用if-then-else语句实现:

选择if-then-else语句还是switch语句,取决于程序的可读性和语句的条件表达式。if-then-else语句可以根据值或条件的范围进行条件判断,而switch语句只能根据单个值(如整数、枚举值、String对象等)进行条件判断。
需要注意的是break语句,它让程序跳出switch语句,继续执行switch块后的第一条语句。break语句是必需的,如果没有break语句,switch块中的语句就会失效:它会顺序执行匹配case标签之后的所有语句,不管是否是表达式的子case标签,直到遇到break语句。程序SwitchDemoFallThrough就是这样一个例子,它输出匹配月份及之后的月份:

程序输出如下:

就技术而言,最后的break不是必需的,因为控制流会跳出switch语句。但建议使用break,因为这样有助于更改代码,而且不容易犯错误。default部分处理所有不能用case部分显式处理的值。
下述SwitchDemo2程序说明语句如何包含多个case标签,其功能为计算特定月份的天数:

输出结果如下:

在switch语句中使用String对象
在switch语句的表达式中可以使用String对象。下面的程序StringSwitchDemo会根据月份的String值来显示月份的数值:


程序输出8。
switch表达式中的String对象与case标签关联的表达式比较,就像使用String.equals方法一样。要让StringSwitchDemo程序接收任意大小写的月份,只需将输入的月份名称转换成小写(使用toLowerCase方法),并将case标签关联的所有字符串都改成小写即可。
注意 这个例子测试switch语句中的表达式是否为null。要确保任意switch语句中的表达式都不为null,以免抛出空指针异常(NullPointerException)。

3.4.3 while语句和do-while语句
当条件为真时,while语句不断执行语句块。其语法如下:

while语句先计算expression的值,并返回一个boolean值。如果其值为真,while语句执行while块中的statement(s)。接着不断执行while代码块,并计算expression的值,直到expression的值为假。使用下述WhileDemo程序可以依次打印1到10的值:

无限循环可以由下面的while语句实现:

Java程序语言也支持do-while语句,其格式如下:

do-while语句和while语句的区别在于do-while在循环的末端计算表达式的值,而不是在顶部。因此,do代码块内的语句至少要执行一次,如DoWhileDemo程序所示。

3.4.4 for语句

for语句提供在一定值范围内迭代的紧凑方式。程序员通常称为for循环,因为在满足特定的条件之前,它会一直循环执行。for语句的一般形式如下:

使用这种形式的for语句时,要牢记以下几点:

  • initialization表达式初始化循环,它只在循环开始时执行一次。
  • 当termination表达式的值为false时,循环终止。
  • 循环过程中,每次迭代都会调用increment表达式,该表达式可以对一个值进行递增或递减操作。

下述ForDemo程序使用for语句的一般形式将数字1到10显示到标准输出上:

输出结果为:

注意如何在initialization表达式中声明变量。变量的作用域为从变量声明到for语句控制的代码块末端,因此它也可以用于termination和increment表达式。如果控制for语句的变量不是循环体外必需的,那么最好在initialization表达式中声明该变量。变量名i、j和k通常用于控制for循环,在initialization表达式内声明这些变量,不仅限制了它们的生命周期,而且会减少错误。
for循环的三个表达式都是可选的。无限循环可以如下创建:

for语句还有另一种形式,用于迭代集合和数组中的元素。这种形式有时称为加强型for语句,主要用于使循环更加紧凑,易于阅读。下面举个例子来说明这一点,数组包含了从1到10的10个数字:

程序EnhancedForDemo使用加强型for语句来循环该数组:

在这个例子中,变量item保存数组numbers的当前值。输出结果和ForDemo的输出结果一样:

建议使用加强型for语句,而不是一般形式的for语句。

3.4.5 分支语句

1.?break语句
break语句有两种形式:标签式和非标签式。非标签式break语句在switch语句的讨论中已经介绍过。如下面的BreakDemo程序所示,非标签式break也可以终止for、while或do-while循环:

该程序在数组中搜索数字12。找到12时,break语句(如上述代码中黑体所示)会终止for循环。控制流会跳转到for循环后面的语句。程序输出结果如下:

非标签式break语句会终止最内层的switch、for、while或do-while语句,而标签式break语句会终止外层语句。下面的BreakWithLabelDemo程序与前述程序类似,只是使用嵌套循环在二维数组中搜索值。找到该值时,标签式break语句(标签式search)会终止外层循环。

程序输出:

break语句会终止标签语句,但不会改变到标签语句的控制流。控制流会立即跳转到标签语句(已终止)后的语句。
2.?continue语句
continue语句会跳出for、while或do-while循环的当前迭代。非标签形式会跳转到最外层循环体的末端,并计算控制该循环的boolean表达式。下面的ContinueDemo程序逐个统计字符串中字母p的出现次数。如果当前字符不是p,continue语句会跳出循环并继续测试下一个字符。如果字符是p,将字母个数加1:

程序输出:

删除continue语句并重新编译,可以清楚地看到continue语句的作用。运行程序时,计数错误,也就是说会搜索到35个p,而不是9个。
标签式continue语句跳出给定标签标记的外层循环的当前迭代。下述Continue-
WithLabelDemo程序使用嵌套循环在另一个字符串内搜索子串。需要用到两个嵌套循环:一个用于迭代待搜索的子串,另一个用于迭代要搜索的字符串。ContinueWithLabelDemo使用标签式continue语句跳出外层循环的迭代:


程序输出:

  1. return语句
    最后一种分支语句是return语句。return语句退出当前方法,且控制流返回到调用方法的位置。return语句有两种形式:一种返回值,另一种不返回值。要返回值,只需在return后输入返回的值或待计算的表达式:

返回值的数据类型必须与方法声明的返回值的类型匹配。当方法声明为void类型时,要采用不返回值的return语句:

第4章将介绍编写方法时所需要的知识。

3.4.6 小结

if-then语句是最基本的控制流语句。该语句使得当某个条件为真时,程序只执行特定的代码段。if-then-else语句在条件为假时提供第二条执行路径。与if-then和if-then-else语句不同,switch语句可以包含多条可能的执行路径。while和do-while语句当条件为真时可以不断执行语句块。do-while语句和while语句的区别在于do-while在循环的末端计算表达式的值,而不是在顶部。因此,do代码块内的语句至少执行一次。for语句提供在一定值范围内迭代的紧凑方式。它有两种形式,其中一种用于迭代集合和数组中的元素。

3.4.7 问题和练习:控制流语句

问题
1. Java程序语言支持的最基本的控制流语句是     
2.      语句支持任意数量可能的执行路径。
3.      语句与while语句类似,但在循环的     计算表达式的值。
4. 如何使用for语句编写无限循环?
5. 如何使用while语句编写无限循环?
练习
根据下述代码段,完成后面的练习:

a.?想象一下,如果aNumber是3,上述代码段会输出什么结果?
b.?编写一个测试程序,它包含前面代码段,而且aNumber的值为3。程序的输出结果是

?什么?输出结果是否就是预期的结果?解释原因。换句话说,什么是该代码段的控
?制流?
c.只使用空格和换行符重新排版代码段,以便理解其控制流结构。
d.使用大括号进一步简化代码。
答案
相关答案参考
http://docs.oracle.com/javase/tutorial/java/nutsandbolts/QandE/answers_flow.html。

时间: 2024-09-08 09:39:15

《Java语言导学(原书第6版)》一3.4 控制流语句的相关文章

《数据结构与抽象:Java语言描述(原书第4版)》一2.1.2 一组核心方法

2.1.2 一组核心方法 基于Java语言数组实现的ADT包吸收了教室示例中展现的一些想法.由此得到了类ArrayBag,它实现了在程序清单1-1中见到过的接口BagInterface.接口中的每个公有方法对应于ADT包的一个操作.我们记得,接口为包中的对象定义了泛型T.我们在ArrayBag的定义中也用到了这个泛型.类ArrayBag的定义可能相当难懂.该类确实有不少的方法.对于这样的类,你不应该定义整个类,然后试图去测试它.而是应该先确定一组核心方法(core method)来实现并测试这些

《数据结构与抽象:Java语言描述(原书第4版)》一P.1 封装

P.1 封装 如果你想学习驾驶,那么对汽车的哪些描述对你最有用?显然不是描述它的发动机如何周而复始地获取空气和汽油,点燃空气和汽油的混合物,然后排出的过程.当你想学习驾驶时,这样的细节是不必要的.事实上,可以以你的方式获知这些细节.如果你想学习驾驶,最有用的汽车描述是如下的这些特点: 如果你将脚踩在油门踏板上,汽车将开得更快. 如果你将脚踩在制动踏板上,汽车将慢下来并最终停止. 如果你将方向盘向右转,汽车将右转. 如果你将方向盘向左转,汽车将左转. 就像你不需要告诉想开车的人发动机是如何工作的一

《数据结构与抽象:Java语言描述(原书第4版)》一练习

练习 1.说明程序清单1-3中给出的类PiggyBank的每个方法:说明方法的目的:描述它的参数:写前置条件.后置条件和方法头的伪代码.然后写一个用于这些方法的Java接口,包括javadoc风格的注释. 2.假定groceryBag是一个包,它被表示不同杂货名字的10个字符串填满了.写Java语句,计数groceryBag中"soup"的出现次数并全部删除.不要从包中删除任何其他的字符串.报告包中出现的"soup"的个数.groceryBag中可能不包含"

《数据结构与抽象:Java语言描述(原书第4版)》一P.4.3 统一建模语言

P.4.3 统一建模语言 图P-4中的用例图是更强大表示法的一部分,这个表示法称为统一建模语言(Unified Modeling Language,UML).设计人员使用UML来说明软件系统中必需的类及它们的关系.UML能给出复杂系统的整体视图,比用自然语言或程序设计语言描述更有效.例如,英语可能有二义性,而Java代码提供更多的细节.给出明确的类之间的交互图,是UML的强项之一.除了用例图之外,UML还能提供类图,类图将每个类的描述放在类似于CRC卡的方框中.方框内包含类名.它的属性(attr

《数据结构与抽象:Java语言描述(原书第4版)》一2.2.1 可变大小数组

2.2.1 可变大小数组 策略.当教室满了时,能容纳更多学生的一种办法是移到一间更大的教室.用类似的方式,当数组满了时,可以将它的内容移到一个更大的数组中.这个过程称为调整(resizing)数组大小.图2-7显示两个数组:一个是有5个连续内存单元的原始数组,另一个数组(两倍于原始数组大小)在计算机的另一块内存中.如果将数据从原始的小数组中复制到新的大数组的开头部分,得到的结果像是扩展了原来的数组一样.这种机制的唯一不足是新数组的名字:你想让它与原始数组同名.马上就会看到如何完成这个工作. 细节

《数据结构与抽象:Java语言描述(原书第4版)》一1.1 什么是包

1.1 什么是包 设想一个纸袋,或反复使用的布袋,甚至一个塑料袋.当人们购物.打包午餐或者吃土豆片时会用到袋子.袋子里装着东西.在日常用语中,包(也称为袋子--译者注)是一种容器.但在Java中,容器(container)是一个对象,它的类派生于标准类Container.这样的容器用在图形程序中.在Java中,不把包(bag)看作一种容器,而是一种集合.包与其他集合的区别是什么呢?包仅仅是含有项,但没有按某种方式规定项的次序,也允许有重复的项.大多数的行为可由其他类型的集合执行.当描述本章中设计

《数据结构与抽象:Java语言描述(原书第4版)》一1.2 说明一个包

可以使用UML将方法表示为: 且将这行添加到类图中.可以使用一个布尔值方法来测试包是否为空,同样该方法没有参数.用伪代码及UML描述这个方法的规格说明 及 将这行添加到类图中. 注:因为通过查看getCurrentSize是否返回0就能检测包何时为空,所以并不真的需要操作isEmpty.但是它是所谓的便利方法(convenience method),所以很多集合都提供这样一个操作.现在想向包中添加给定的对象.可以将这个方法命名为add,并有一个表示新项的参数.可以写出下列伪代码: 我们可能试图让

《数据结构与抽象:Java语言描述(原书第4版)》一2.1.3 实现核心方法

2.1.3 实现核心方法 数据域.在定义任何核心方法之前,需要考虑类的数据域.因为包要保存一组对象,所以一个域是这些对象的数组.数组的长度定义了包的容量.可以让客户指定这个容量,我们也可以提供一个默认容量.另外,我们想跟踪包中当前项的个数.所以可以为我们的类定义如下的数据域: 并将它们加到图1-2中类的UML表示中.得到的表示如图2-2所示. 程序设计技巧:终态数组 通过声明数组bag是类ArrayBag的一个终态数据成员,可知变量bag中的引用不能改变.虽然以这种方式声明数组是一种好的做法,但

《数据结构与抽象:Java语言描述(原书第4版)》一JI2.1 基础

JI2.1 基础 当在一个方法内发生异常时,该方法创建一个异常对象,并将它传给Java运行时系统.我们说方法抛出(throw)一个异常.被抛出的异常是发给程序的其他部分的一个信号,表示某些意外的事情发生了.根据异常类的类型,以及异常对象通过其方法告诉我们的信息,代码可以对其进行适当的响应处理.当发现并响应异常时,就是处理(handle)异常. 异常属于不同的类,不过所有这些类都是标准类Throwable的后代.Throwable在Java类库中,不需要import语句就可以使用.异常分为以下三组

《数据结构与抽象:Java语言描述(原书第4版)》一1.4 像使用自动贩卖机一样使用ADT

1.4 像使用自动贩卖机一样使用ADT 假定你站在一台自动贩卖机前,如图1-3所显示,或者更高级的一台,休息一下,然后从贩卖机中买些东西! 当站在自动贩卖机前时,会看到它的界面.投入硬币并且按下按钮,就能购物了.下面是对自动贩卖机的观察结果: 你仅能执行机器的界面提供给你的特定任务. 你必须理解这些任务--即你必须知道买一瓶汽水应该怎么办. 你不能访问机器内部,因为锁着的外壳封装了它. 即使你不知道内部将发生什么,但你可以使用机器. 如果有人用改进版替换了机器内部的机制但没改变界面,你仍然能用同