转载

Java编程入门(3.3):while与do..while语句

Java支持简单语句和复合语句。比如赋值和子函数调用这样的简单语句是构建程序的基础模块。像while循环和if语句这样的复合语句用来将简单语句组织成复杂的结构。这种结构被称作控制结构,用来控制语句的执行顺序。下面的五个章节会讨论Java中的控制结构,从本节的while语句和do…while语句开始介绍。与此同时,我们会给出每种控制结构的示例程序并将其应用到 前一节 算法设计例子中。

3.3.1  while循环

在之前的 3.1节 中已经介绍了while循环,结构如下:

while ( boolean-expression )    statement

while语句是一个代码块,由一组语句组合在一起并包含在一对括号中。结构中的statement被称作循环体。当boolean-expression为true时,会循环执行循环体中的语句。这个布尔表达式被称作循环条件,执行简单的测试。有几点需要澄清。在循环体一次都没有执行前,循环条件为false时会发生什么?这种情况下,循环体永远不会执行。while循环的主体可能会任性任意多次,当然也可能是0次。当执行到循环体 中间 某条语句时循环条件由true变为false时会怎么样?会马上结束循环吗?不会,因为计算机会一直执行到循环结束为止。只有当重新跳转到循环开始并且测试循环条件时,循环才会结束。

让我们来看看使用while循环解决问题的一个典型示例:用户输入一组正整数,算出它们的平均值。平均值的算法,是所有整数的和除以整数个数。程序会要求用户每次输入一个整数,记录输入整数的个数,然后计算所有已录入数字的和。下面是这段程序的伪代码:

Let sum = 0     // 保存用户输入所有整数的和 Let count = 0   // 保存用户输入的整数个数 当还有整数要处理时:     读入一个整数     加到sum变量     为count增加计数 用sum除以count得到平均值 输出平均值

如何知道还有待输入的整数呢?一种典型的解决方法是,让用户在所有数据录入完毕时输入0。这种方法在所有数据都是正整数的情况下有效,这时0不是一个合法的数值。0本身不作为计算平均数集合中的数据,仅仅作为真实数据录入结束的标志。这种方法一些场合下被称为使用哨兵值。所以,现在while循环的测试条件变为“当输入的整数非0”。但是这里有另外一个问题!第一次判断循环条件时,循环体尚未执行,这时还没有读取任何数值。也就是说,还没有“输入的整数”。这时判断输入整数是否为0是没有意义的。因此,我们需要在循环执行 做一些处理,把必要的信息准备好。这里,我们只要在循环的前面读取第一个整数就可以了。下面是修改后的算法:

Let sum = 0 Let count = 0 读取一个整数 整数非0时:     将整数加到sum     增加count计数     读取一个整数 用sum除以count得到平均值 输出平均值

请注意,这里我重新调整了循环体。由于在循环开始前就读取了整数,在循环一开始就需要处理读到的整数。在循环的最后,计算机会读取一个新的整数。计算机会跳转到循环开始的地方,用新读取的值测试循环条件。注意:当计算机读取最后的哨兵值以后,会直接结束循环而不对其进行处理。既不会累计到sum中,也不会算到count里。这就是算法的工作机制。哨兵值不作为数据的一部分。在最初的算法中,不做循环前的准备会累计所有的值包括哨兵值,所以结果是错的。(哨兵值为0,因此sum的结果是正确的,但是count会多算了1个。这种常见的错误被称作“差一错误”。循环中进行计数会比看上去难得多!)

可以很容易地把算法转换成一个完整的程序。注意,在程序中不能用“average = sum/count;”这样的语句计算平均值。因为sum和count都是int类型,sum/count的结果是整数,而平均值应该是实数。我们之前已经遇到过了这个问题:把其中一个int值转换为double类型,强制计算机把商值作为实数计算。具体的做法,将其中一个变量强制类型转换为double。“(double)sum”将sum值转为实数,因此计算平均数可以改成“average = ((double)sum) / count;”。还有一种方法,把声明变量时就声明为double类型。

程序还存在另一个问题:用户一开始输入0时,程序不会再处理其它输入。这种用例可以来测试循环结束时count是否还等于0。看起来这是细节问题,但是仔细的程序员应该考虑所有的情况。

下面是程序的完整代码:

/**  * 这个程序会读取一个用户输入的正整数序列,  * 输出所有整数的平均值。  * 程序会提示用户每次输入一个整数。  * 当用户输入0时表示输入结束。  * (0不会作为数据加入平均值计算)  * 该程序不会检查用户输入是否为正整数,  * 即使输入负数也会加入计算。  */  public class ComputeAverage {     public static void main(String[] args) {        int inputNumber;   // 用户输入       int sum;           // 正整数和       int count;         // 输入的正整数个数       double average;    // 平均数        /* 初始化sum和count变量*/       sum = 0;       count = 0;        /* 读取并处理用户输入 */       System.out.print("Enter your first positive integer: ");       inputNumber = TextIO.getlnInt();        while (inputNumber != 0) {          sum += inputNumber;   // 把inputNumber累加到sum          count++;              // count加1          System.out.print("Enter your next positive integer, or 0 to end: ");          inputNumber = TextIO.getlnInt();       }        /* 打印计算结果 */       if (count == 0) {          System.out.println("You didn't enter any data!");       }       else {          average = ((double)sum) / count;          System.out.println();          System.out.println("You entered " + count + " positive integers.");          System.out.printf("Their average is %1.3f.n", average);       }     } // end main()  } // end class ComputeAverage

3.3.2  do..while语句

有时候,在循环结尾测试循环条件会比像while循环那样开头判断更加方便。do..while语句与while循环非常类似,区别在于“while”及循环体被移到了结尾,在循环的开头添加了“do”。do..while语句的结构如下:

do     statement while ( boolean-expression );

通常情况下,statement可能是一个代码块:

do {     statements } while ( boolean-expression );

注意:在do..while的结尾有一个分号“;”。这个分号也是语句的一部分,与赋值语句或声明语句结尾的分号一样。漏写分号会造成语法错误。(通常, 每个 Java语句都会以分号或右花括号“}”结尾)

执行do循环时,计算机会首先执行循环体中的语句,然后判断循环条件。如果循环条件表达式为true,计算机会回到do循环开头继续执行;如果为false,计算机会终止循环继续执行程序的其它部分。由于只有在循环末尾才会进行条件判断,do循环至少会执行一次循环体。

例如,下面的伪代码是一个游戏程序。使用do循环比起while循环更有意义,至少能玩一盘游戏。程序的开始版本,循环判断条件没有意义:

do {    玩一盘游戏    询问是否想要再玩一盘    读取反馈 } while ( 用户的反馈是 yes );

把上面的伪代码转成Java。开始不去讨论游戏的细节,让我们定义一个Checkers类,其中包含了一个static成员函数叫做playGame(),和程序的使用者玩跳棋游戏。伪代码“玩一盘游戏”被转换为调用“Checkers.playGame();”。我们需要一个变量存储用户的反馈。TextIO类通过一个boolean变量存储 yes/no 的回复结果。“Yes”表示true,“no”表示false。因此算法的代码会变成:

boolean wantsToContinue;  // True表示用户想要再玩一盘 do {    Checkers.playGame();    System.out.print("Do you want to play again? ");    wantsToContinue = TextIO.getlnBoolean(); } while (wantsToContinue == true);

当boolean变量的值变为false,表示循环应当结束。在程序的一个地方赋值,在另一个地方作为判断条件——当boolean变量这样使用时,被称为标志(flag)或标志变量(表示信号标志)。

顺便说一下,程序员通常会鄙视这样的写法“while (wantsToContinue == true)”。这种方式过于教条,可以用“while (wantsToContinue)”代表同样的含义。类似的,还有“flag == false”这样的写法,flag是一个boolean变量。“flag == false”与“!flag”完全等价,这里的感叹号!表示对boolean值进行取反操作。所以,可以用“while (!flag)”取代“while (flag == false)”,用“if (!flag)”取代“if (flag == false)”。

尽管do..while语句有时候比while语句更加方便,但是两种循环并没有让语言更强大。任何可以用do..while循环解决的问题都可以用while完成,反之亦然。事实上doSomething可以代码任何一个代码块:

do {     doSomething } while ( boolean-expression );

与下面的代码功能一致:

doSomething while ( boolean-expression ) {     doSomething }

类似的,

while ( boolean-expression ) {     doSomething }

可以替换为:

if ( boolean-expression ) {    do {        doSomething    } while ( boolean-expression ); }

程序的功能没有任何变化。

3.3.3  break和continue语句

while循环与do..while循环会在程序的开始或结尾测试循环条件。有时候,在循环体中间或者几个不同的地方测试条件会更加合理。Java提供了在循环体中跳出循环的通用方法,叫做break语句,形式如下:

break;

当计算机在循环体重执行break语句时,会立刻跳出循环。接下来会继续执行循环后面的语句。考虑下面的示例:

while (true) {  // 看起来会一直循环下去!    System.out.print("Enter a positive number: ");    N = TextIO.getlnInt();    if (N > 0)   // 输入OK,跳出循环       break;    System.out.println("Your answer must be > 0."); } // continue here after break 在break执行后,从这里开始继续执行

如果用户输入的数值大于0,会执行break语句跳出循环。否则,计算机会输出“Your answer must be > 0.”然后跳转到循环的开头继续读取其它用户输入的值。

循环的第一行,“while (true)”可能会有一点奇怪,但确是合法的。while循环的条件可以是任意boolean类型的表达式。计算机会判断检查式的值看是true还是false。boolean值“true”也是一个boolean表达式,值为true。所以,“while (true)”表示无限循环,可以通过break语句终止无限循环。

break语句会立刻终止包含了该语句的循环。Java支持循环嵌套,即一个循环中包含另一个循环。如果在嵌套的循环内调用break语句,只会跳出该层循环,而非跳出外层循环。还有一种跳转叫做标签中断(labeled break),可以指定希望跳出的循环。这种用法并不常见,这里我会快速带过。标签(Label)的工作方式如下:可以在任何循环前面加上标签。标签由一个简单标识符带一个冒号组成。例如,带label的while循环看起来像这样“mainloop: while…”,在循环内部,你可以使用带标签的跳转语句,比如“break mainloop;”来跳转带标签的循环。例如,下面这段代码检查两个字符串,s1和s2,有一个共同的字符。如果找到共同字符,标志变量nothingInCommon会置为false,通过标签中断结束处理:

boolean nothingInCommon; nothingInCommon = true;  // 假设s1和s2没有共同字符 int i,j;  // 在s1和s2中用来循环的迭代变量  i = 0; bigloop: while (i < s1.length()) {    j = 0;    while (j < s2.length()) {       if (s1.charAt(i) == s2.charAt(j)) { // s1和s2有共同的字符           nothingInCommon = false;           break bigloop;  // 跳出所有2层循环       }       j++;  // 继续处理s2中的下一个字符    }    i++;  // 继续处理s1中的下一个字符 }

continue语句与break类似,但是很少使用。continue语句告诉计算机跳过本次循环剩余语句的执行。然而,与跳出循环不同,continue会跳转到循环开始继续下一次迭代(包括判断循环变量的值是否需要继续迭代)。与break语句类似,在嵌套循环中执行continue语句时,会直接转到包含该语句的循环开始;“标签继续(labeled continue)“会转到指定的循环继续执行。

break和continue语句可以用在while循环与do..while循环中。它们也可以在 接下来的章节 中介绍的循环中使用。在 3.6节 ,我们会看到在switch语句中使用break。break还可以在if语句中使用,前提是if语句嵌套在循环火种switch语句中。在这种情况下,break并 意味着会跳出if语句,而是跳出包含着if语句的循环或switch语句。在if语句中使用continue也是类似的用法。

原文链接: math.hws.edu 翻译:ImportNew.com -唐尤华

译文链接:[]
原文  http://www.importnew.com/19967.html
正文到此结束
Loading...