Java编程入门(3.1):代码块、循环和分支

代码块、循环和分支


将简单命令按照一定方式组合为控制结构,计算机具备了执行复杂任务的能力。在Java中,有6种控制结构决定了程序正常的控制流程。事实上,只需要其中3种就足以完成几乎任何编程任务。这6种控制结构分别是:代码块、while 循环、do..while 循环、for 循环、if 语句和 switch 语句。每一种结构都可以被看成独立的“语句”,但是结构化的语句可以在其内部包含一种或多种其它语句。


3.1.1  代码块

代码块是最简单的结构化语句。它的目的是将一组语句组成一个语句。代码块的格式如下:

{
     statements
}

也就是说,代码块包含了一组由括号 ”{” 和 “}”包围的语句序列。事实上,括号里也可以不包含任何语句,只有一对空的括号,称为空代码块。空代码块在某些情况下也是有用的。代码块语句通常包含在其它语句中,其目的就是将若干语句合并为一个单元。然而,任何语句可以出现的地方代码块也可以合法地存在。有一个地方需要使用代码块:你可能已经注意到程序中的 main 方法,这个子程序的定义就是一个代码块,由一对括号包围着一系列语句。

这里或许应该再强调一点,Java是一种所谓的自由格式语言(free-format language)。没有任何语法规定代码要怎样排版。如果你喜欢,可以在一行中书写整段代码。出于良好编程风格的考虑,在编写自己程序的时候,你应当尽可能做到结构清晰。通常,这意味着每个语句单独成为一行,使用缩进来表示语句归属于哪个控制结构。我在自己的示例中都采用了这种结构。

下面是两个代码块示例:

{
   System.out.print("The answer is ");
   System.out.println(ans);
}

{  // This block exchanges the values of x and y 这段代码将x和y的值进行了交换
   int temp;      // A temporary variable for use in this block. A是这段代码中的临时变量
   temp = x;      // Save a copy of the value of x in temp. 在temp中保存x值的拷贝
   x = y;         // Copy the value of y into x. 拷贝y的值给x
   y = temp;      // Copy the value of temp into y. 拷贝temp值给y
}

在第二个例子里,代码块中声明了temp变量 。这是完全合法的。声明的变量只在这段代码中使用,代码块之外完全不能访问也无法看到这个变量,这是一种很好编程风格。声明变量时,计算机分配了一块内存用来存储变量的值。在执行到代码块的结尾时,会丢弃这块内存(也就是说,这块内存可以再次使用了)。这样的变量成为该代码块的本地变量。有一个普遍的概念叫做标识符的“作用域”,即标识符在程序中的有效范围。变量只在本代码块内有效,具体地说是在变量声明后有效。


3.1.2  简单while循环

代码块语句本身并不影响程序的控制流。另外5种控制结构对控制流会有影响。这5种控制结构分为两类:循环语句和分支语句。只有具备循环语句和分支语句才可以算得上是一门完整的通用编程语言,其它的高级功能是让使用更加方便而已。本节中,我会介绍 while 循环和 if 语句。在接下来的章节中,我会详细介绍这些语句以及其它三种控制结构。

while 循环可以不断重复执行特定语句。当然,你肯定不会希望永远这样执行下去。这样会变成无限循环,那是一件很糟糕的事情。(有一个发生在计算机先驱Grace Murray Hopper女士身上的老掉牙故事,她在洗发水上读到这样的说明:“打肥皂、漂洗、再来一遍”。据说她按照说明书的指令执行,最后洗发水都用完了。(为了防止你没有发现笑点,这是一个关于计算机盲目执行指令的笑话))

(译者注:Grace Murray Hopper是杰出的计算机科学家,Cobol语言的主要设计者)

更具体地说,只要指定的条件为 true,while 循环会一直重复执行一条语句。while 循环的形式如下:

while (boolean-expression)
     statement

由于循环执行的语句通常是一个代码块,大多数的 while 循环形式如下:

while (boolean-expression) {
    statements
}

一些程序员认为,这些括号应当作为编程风格存在,即使括号中只有一条语句也需要保留。我并不这么认为。

while 循环的语义:当计算机执行到 while 语句时,首先计算布尔表达式的值,得到结果为 true 或 false。如果条件为 false,那么计算机会跳过 while 循环余下的部分,继续执行程序中的下一条语句。如果条件为 true,计算机会继续执行循环内的语句或代码块,跳转到 while 循环重复这个流程。也即重新计算布尔表达式的值,结果为 false 时结束循环,结果为 true 继续执行。循环往复,直到计算机发现表达式的值为 false。如果表达式的值永远不为 false,就会变成无限循环。

下面是一个 while 循环示例,简单地打印出数字1、2、3、4、5:

int number;   // The number to be printed. 待输出的数字
number = 1;   // Start with 1. 从1开始
while ( number < 6 ) {  // Keep going as long as number is < 6. 只要number小于6,继续执行
    System.out.println(number);
    number = number + 1;  // Go on to the next number. 继续执行下一个数字
}
System.out.println("Done!");

number 变量初始化时值为1。所以,当计算机第一次计算表达式 “number < 6″ 时,会判断 1 是否小于 6,结果为 true。因此,计算机继续执行循环中后面两条语句。第一条语句输出结果“1”。第二条语句将 number 变量值加 1,然后存回 number 变量。这时 number 的值变为 2。当计算机执行到循环结束时,它会返回到开头的地方,继续判断 number 变量是否小于 6。一旦结果返回 true,计算机会再次执行这个循环。这一次,程序会输出 2 并将 number 的值改为 3。按照这个方式循环下去,直到 number 的值等于 6。这个时候 “number < 6″ 表达式返回 false。因此,计算机会调过循环的结尾执行下一条语句,最后输出消息 “Done!”。请注意,当循环结束时,number 的值为 6,但是最后一次输出的值为 5。

顺便说一下,你应该知道在一个实际程序中从来不会看到只有一个 while 循环。通常它会出现在一个子程序中,而子程序会在某个类中。这里有一个完整的程序,程序的功能是计算近几年的投资利息。程序中使用了一个 while 循环。这是对前一章示例程序的改进,只报告一年的结果。

/**
 *  This class implements a simple program that will compute the amount of 
 *  interest that is earned on an investment over a period of 5 years.  The 
 *  initial amount of the investment and the interest rate are input by the 
 *  user.  The value of the investment at the end of each year is output.
 *  这个类实现了一个简单的程序。用来计算5年来的投资利息。
 *  投资的本金和利率由用户输入。最后输出每一年结束时的投资净值。
 */

public class Interest3 {

   public static void main(String[] args) {

      double principal;  // The value of the investment. 投资总额
      double rate;       // The annual interest rate. 年利率

      /* Get the initial investment and interest rate from the user. */
      /* 由用户输入初始投资和利率 */

      System.out.print("Enter the initial investment: ");
      principal = TextIO.getlnDouble();

      System.out.println();
      System.out.println("Enter the annual interest rate.");
      System.out.print("Enter a decimal, not a percentage: ");
      rate = TextIO.getlnDouble();
      System.out.println();

      /* Simulate the investment for 5 years. */
      /* 模拟5年的投资过程 */

      int years;  // Counts the number of years that have passed. 投资开始的年数

      years = 0;
      while (years < 5) {
         double interest;  // Interest for this year. 当年的利息
         interest = principal * rate;
         principal = principal + interest;     // Add it to principal. 把利息增加到本金
         years = years + 1;    // Count the current year. 计算当前的年数
         System.out.print("The value of the investment after ");
         System.out.print(years);
         System.out.print(" years is $");
         System.out.printf("%1.2f", principal);
         System.out.println();
      } // end of while loop while循环结束

   } // end of main() main函数结束

} // end of class Interest3 Interest3类结束

你应当仔细研究这个程序,并确保已经理解计算机执行 while 循环的每一步。


3.1.3  简单 If 语句

if 语句告诉计算机,根据给定的布尔表达式值为 true 或 false,从两个可选的方案中选择一种执行。它是一种“分支”或“判定”语句。if 语句的形式如下:

(译者注:译文中的“if 语句 if statement” 指 “if .. else”结构)

if ( boolean-expression )
    statement1
else
    statement2

当计算机执行 if 语句时,会计算布尔表达式的值。如果值为 true,计算机会执行第一条语句,跳过“else”后面的语句。如果值为 false,计算机会跳过第一条语句,执行第二条语句。请注意,在任何情况下,if 语句中有且只有一条语句会执行。两条语句分别表示可选的执行方案,而计算机会基于布尔表达式的值进行选择。

很多时候,你会希望计算机要么执行、要么不执行一些语句。可以通过不带 else 的 if 语句实现。

if ( boolean-expression )
    statement

要执行这条语句,计算机会计算表达式的值。如果值为 true,计算机会执行 if 语句内的部分;如果值为 false,计算机会跳过不执行那条语句。无论哪种情况,计算机都会继续执行程序中接在 if 语句后面的语句。

有时候,新手程序员会把 while 语句和(没有else的)简单 if 语句搞混,尽管它们的含义非常不同。if 中的语句最多只能执行一次,而 while 中的语句可以执行很多次。通过下面的控制流程图有助于理解 while 和简单 if 语句:

Control flow diagrams for while and simple if

在上面的图中,箭头表示语句执行的时间流转。控制流从图的上方开始,在底部结束。类似的,if..else 语句的控制流程图清晰地表示了两个嵌套语句中只有一条会被执行:

Control flow diagram for if..else statement


当然,if 语句中的任意一条或两条都可以是代码块。同样的,很多程序员都喜欢在只有一条语句的情况下加上括号。因此,通常 if 语句看起来像下面这样:

if ( boolean-expression ) {
    statements
}
else {
    statements
}

或者这样:

if ( boolean-expression ) {
    statements
}

下面是用 if 语句交换 x、y 两个变量值的示例,只有当 x 大于 y 的时候才会执行。在 if 语句执行之后,我们可以确定 x 的值小于等于 y:

if ( x > y ) {
    int temp;      // A temporary variable for use in this block. 在代码块中使用的临时变量。
    temp = x;      // Save a copy of the value of x in temp. 将x的值保存一份拷贝到temp。
    x = y;         // Copy the value of y into x. 拷贝y的值到x。
    y = temp;      // Copy the value of temp into y. 拷贝temp的值到y。
}

最后,这是一个带有 else 的 if 语句。看看你能否指出这段语句的功能,以及为什么会这样使用:

if ( years > 1 ) {  // handle case for 2 or more years 处理2年及2年以上的情况
    System.out.print("The value of the investment after ");
    System.out.print(years);
    System.out.print(" years is $");
}
else {  // handle case for 1 year 处理1年的情况
    System.out.print("The value of the investment after 1 year is $");
}  // end of if statement if语句结束
System.out.printf("%1.2f", principal);  // this is done in any case 任何情况下都会执行

在这一章,我会讨论更多关于控制结构的内容。但是你已经了解了最重要的部分。即使你从未学过任何控制结构知识,现在应该已经具备足够的知识可以进行计算。简单循环和分支是你真正需要的东西!


3.1.4  明确赋值

在介绍控制结构的最后,我会以一个稍微困难的问题结束。在你第一次遇到这个问题时可能不会完全理解。考虑下面两段代码,看上去似乎完全一样:

int y;                          int y;
if (x < 0) {                    if (x < 0) {
    y = 1;                           y = 1;
}                               }
else {                          if (x >= 0) {
    y = 2;                           y = 2;
}                               }
System.out.println(y);          System.out.println(y);

左边的这段代码中,如果 x < 0 会将 y 赋值为 1;否则 x >= 0,会将 y 赋值为 2。与右边的版本一模一样。然而,还是有一些细微的差别,事实上,Java编译器会对右边代码中的 System.out.println 语句报告错误,而左边的代码却没有问题!

问题在于,计算机无法分辨右边的代码是否确定已被赋值。如果 if 语句没有 else 部分,那么 if 语句内部的程序可能执行也可能不执行,完全取决于条件的值。编译器不能判断语句最终是否执行,因为条件只会在程序执行时进行判断。右边的代码对编译器而言,有可能 y = 1 和 y = 2 都不会执行。因此,程序可能会输出未定义的值。编译器认为这是一个错误。只有在程序执行的那个时刻,编译器才能确认变量会被赋值。这就是所谓的明确赋值。(在这个例子中,当然可以知道 y 一定会被赋值。但问题的关键是编译器是否知道。)

请注意,在左边这段代码中,y 肯定会被赋值,因为它在 if..else 语句中。无论 if 的条件值是什么,两个可选方案中必定有一个会执行。理解 if..else 和 两个简单的 if 语句之间的区别非常重要。下面是另一对代码段,它们看起来做了同样的事情,但实际上不是。x 语句执行后的结果是什么呢?

int x;                             int x;
x = -1;                            x = -1;
if (x < 0)                         if (x < 0)
    x = 1;                             x = 1;
else                               if (x >= 0)
    x = 2;                             x = 2;

左边代码执行后,x 的值是 1;而右边执行后,x 的值是 2。


原文链接: math.hws.edu 翻译: ImportNew.com - 唐尤华
译文链接: http://www.importnew.com/17253.html
[ 转载请保留原文出处、译者和译文链接。]

关于作者: 唐尤华

我喜欢程序员,他们单纯、固执、容易体会到成就感;面对压力,能够挑灯夜战不眠不休;面对困难,能够迎难而上挑战自我。他们也会感到困惑与傍徨,但每个程序员的心中都有一个比尔盖茨或是乔布斯的梦想“用智慧开创属于自己的事业”。我想说的是,其实我是一个程序员。(新浪微博:@唐尤华

查看唐尤华的更多文章 >>



相关文章

发表评论

Comment form

(*) 表示必填项

还没有评论。

跳到底部
返回顶部