控制流语句

 

通常,源文件中的语句按照它们出现的顺序从头到尾执行。但是,控制流语句(control flow statement)通过使用决策、循环和分支来改变执行流程,使程序按照条件执行特定的代码块。这一节介绍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是所有控制流语句中最基础的语句。只有特定检测结果为true时,它才通知程序执行特定代码段落。例如,只在自行车处于行进状态时,Bicycle类才允许使用刹车降低自行车的速度。下面是applyBrakes方法的一种可能实现:

void applyBrakes(){

  if (isMoving){       // the "if" clause: bicycle must moving

      currentSpeed--;   // the "then" clause:

                           // decrease current speed

  }

}

如果测试结果为false(就是说自行车不在行进状态),那么控制就跳转到if-then语句的结尾。

另外,如果then子句只包含一个语句,那么前后括号是可选的:

void applyBrakes(){

  if (isMoving) currentSpeed--; // same as above,

                                       // but without braces

}

决定什么时候省略括号是个人习惯问题。省略括号会导致代码更加脆弱。如果以后在then子句中加入第二个语句,常见的错误是忘记加上现在必需的括号。编译器不能捕获这样的错误;你将会得到错误的结果。

2. if-then-else语句

当if子句的计算结果为false时,if-then-else语句提供第二个执行路径。在applyBrakes方法中,如果自行车在没有行进时使用刹车,你可以使用if-then-else语句采取某些措施。在这个例子中,采取的措施是简单地输出错误消息,说明自行车已经停住了。

void applyBrakes(){

  if (isMoving) {

      currentSpeed--;

  } else {

      System.err.println("The bicycle has already stopped!");

  }

}

下面的程序IfElseDemo根据考试成绩的值评出等级:如果得分为90或以上,则等级为A;如果得分80或以上,则为B,依此类推。

class IfElseDemo {

  public static void main(String[] args) {

    int testscore = 76;

    char grade;

    if (testscore >= 90) {

        grade = 'A';

    } else if (testscore >= 80) {

        grade = 'B';

    } else if (testscore >= 70) {

        grade = 'C';

    } else if (testscore >= 60) {

        grade = 'D';

    } else {

        grade = 'F';

    }

    System.out.println("Grade = " + grade);

  }

}

程序的输出为:

Grade = C

可能你注意到,testscore的值能满足复合语句中的多个表达式:76 >= 70和76 >= 60。但是,一旦满足条件,会执行适当语句(grade = 'C';),而不会计算其余条件。

3.4.2  switch语句

与if-then和if-then-else语句不同,switch语句允许使用任意数量的可能执行路径。switch语句可以处理byte、short、char和int基本数据类型。它也可以处理4.5节中讨论的枚举类型(enumerated type),还可以处理“包装”特定原始类型的几个特殊类:Character、Byte、Short和Integer,第8章中讨论这些类。

下面的程序SwitchDemo声明int类型的month变量,这个变量表示一年中的月份。程序使用switch语句,按照month的值输出月份名称。

class SwitchDemo {

  public static void main(String[] args) {

    int month = 8;

    switch (month) {

      case 1:  System.out.println("January"); break;

      case 2:  System.out.println("February"); break;

      case 3:  System.out.println("March"); break;

      case 4:  System.out.println("April"); break;

      case 5:  System.out.println("May"); break;

      case 6:  System.out.println("June"); break;

      case 7:  System.out.println("July"); break;

      case 8:  System.out.println("August"); break;

      case 9:  System.out.println("September"); break;

      case 10: System.out.println("October"); break;

      case 11: System.out.println("November"); break;

      case 12: System.out.println("December"); break;

      default: System.out.println("Invalid month.");break;

    }

  }

}

在这个例子中,“August”被发送到标准输出。

switch的语句体被称为switch块(switch block)。switch块直接包含的任何语句都可以使用一个或者多个case或default标签加以标记。switch语句计算其表达式,然后执行适当的case语句。

当然,你也可以使用if-then-else语句实现相同操作:

int month = 8;

if (month == 1) {

    System.out.println("January");

} else if (month == 2) {

    System.out.println("February");

}

... // and so on

决定使用if-then-else语句还是switch语句,有时候是判断的问题。你可以根据可读性和其他因素决定采用哪种语句。If-then-else语句可以用于根据某范围的值或条件进行判断,而switch语句只用于根据单个整数值或者枚举值进行判断。

switch语句中另一个有意思的地方是每个case语句后面的break语句。break语句终止包含它的switch语句,控制流程从switch代码块后的第一个语句继续执行。break语句是必需的,因为如果没有break语句,将继续执行下面的case语句。也就是说,如果没有显式的break语句,流程控制将一个接一个地执行后续的case语句。下面的程序SwitchDemo2演示让case语句连续执行为什么可能是有用的:

class SwitchDemo2 {

  public static void main(String[] args) {

    int month = 2;

    int year = 2000;

    int numDays = 0;

    switch (month) {

      case 1:

      case 3:

      case 5:

      case 7:

      case 8:

      case 10:

      case 12:

         numDays = 31;

        break;

      case 4:

      case 6:

      case 9:

      case 11:

         numDays = 30;

         break;

      case 2:

        if ( ((year % 4 == 0) && !(year % 100 == 0))

              || (year % 400 == 0) )

          numDays = 29;

        else

          numDays = 28;

        break;

      default:

        System.out.println("Invalid month.");

        break;

    }

    System.out.println("Number of Days = " + numDays);

  }

}

程序的输出是:

Number of Days = 29

从技术上说,最后的break语句不是必需的,因为流程总会执行到switch语句之外。但是,我们建议在最后一个case语句中也使用break语句,以便更容易修改代码并减少出错的可能。default部分处理没有被任何case语句显式处理的所有值。

3.4.3  while和do-while语句

当特定条件为true时,while语句持续执行一个代码块。其语法可以表示为:

while (expression) {

  statement(s)

}

while语句计算表达式expression,它必须返回一个布尔值。如果表达式的计算结果为true,那么while语句就执行while块中的语句statement(s)。while语句继续检测表达式并且执行它的块,直到表达式的计算结果为false。下面的程序WhileDemo使用while语句输出从1到10的值:

class WhileDemo {

  public static void main(String[] args){

    int count = 1;

    while (count < 11) {

      System.out.println("Count is: " + count);

      count++;

    }

  }

}

还可以使用while语句实现无限循环,如下:

while (true){

  // your code goes here

}

Java编程语言还提供do-while语句,可以表示为:

do {

    statement(s)

} while (expression);

do-while和while语句之间的区别在于,do-while在循环结尾处(而不是开始处)计算其表达式。因此,do块中的语句总会至少执行一次,如下面的程序DoWhileDemo所示:

class DoWhileDemo {

  public static void main(String[] args){

    int count = 1;

    do {

        System.out.println("Count is: " + count);

        count++;

    } while (count <= 11);

  }

}

3.4.4  for语句

for语句提供了对一个范围内的值进行迭代的紧凑方式。程序员经常把它称为“for循环”,这是因为它的运行方式是重复循环,直到满足特定条件为止。for语句的一般形式可以表示为:

for (initialization; termination; increment) {

  statement(s)

}

在使用for语句的这个版本时,要牢记:

l Initialization(初始化)表达式对循环进行初始化;它在循环开始时执行一次。

l 当termination(终止)表达式计算结果为false时,循环终止。

l 在循环的每次迭代之后调用increment表达式;最常见的方式是使用这个表达式递增或者递减一个值。

下面的程序ForDemo使用for语句的一般形式把数字1到10发送到标准输出:

class ForDemo {

  public static void main(String[] args){

    for(int i=1; i<11; i++){

      System.out.println("Count is: " + i);

    }

  }

}

这个程序的输出为:

Count is: 1

Count is: 2

Count is: 3

Count is: 4

Count is: 5

Count is: 6

Count is: 7

Count is: 8

Count is: 9

Count is: 10

注意初始化表达式中声明变量的代码。这个变量的作用域是从其声明开始,直到for语句控制块的结束,所以它也可以用在终止和递增表达式中。如果在循环之外不需要控制for语句的变量,那么最好在初始化表达式中声明变量。i、j和k这样的名称经常用于控制for循环;在初始化表达式中声明它们,就限制了它们的生存周期并且减少了错误的可能。

for循环的三个表达式都是可选的;可以像下面这样创建无限循环:

for ( ; ; ) {     // infinite loop

  // your code goes here

}

for语句还有另外一种形式,这种形式用于在集合(参见11章)和数组(参见3.1.3节)之中进行迭代。有时候把这种形式称为增强的for(enhanced for)语句,它可以使循环更加紧凑和容易阅读。为了演示,参考下面的数组,它保存数字1到10:

 
  
 

int[] numbers = {1,2,3,4,5,6,7,8,9,10};

下面的程序EnhancedForDemo使用增强for循环遍历这个数组:

class EnhancedForDemo {

  public static void main(String[] args){

    int[] numbers = {1,2,3,4,5,6,7,8,9,10};

    for (int item : numbers) {

      System.out.println("Count is: " + item);

    }

  }

}

在这个例子中,变量item保存从数字数组获得的当前值。这个程序的输出和前一个程序相同:

Count is: 1

Count is: 2

Count is: 3

Count is: 4

Count is: 5

Count is: 6

Count is: 7

Count is: 8

Count is: 9

Count is: 10

我们建议,只要情况允许,就使用for语句的这种形式,而不使用其一般形式。

3.4.5  分支语句

1. break语句

break语句有两种形式:带标签和无标签。在前面讨论switch语句时,你已经见到了无标签形式。

也可以使用无标签的break语句终止for、while或者do-while循环,如下面的程序BreakDemo所示:

class BreakDemo {

  public static void main(String[] args) {

    int[] arrayOfInts = { 32, 87, 3, 589, 12, 1076,

                                2000, 8, 622, 127 };

    int searchfor = 12;

    int i;

    boolean foundIt = false;

    for (i = 0; i < arrayOfInts.length; i++) {

      if (arrayOfInts[i] == searchfor) {

        foundIt = true;

        break;

      }

    }

    if (foundIt) {

        System.out.println("Found " + searchfor +

                                              " at index " + i);

    } else {

        System.out.println(searchfor + " not in the array");

    }

  }

}

这个程序在数组中搜索数字12。当找到这个值时,以粗体显示的break语句终止循环。然后控制流转到程序结尾的输出语句。

这个程序的输出是:

Found 12 at index 4

无标签break语句终止最内层的switch、for、while或do-while语句,而带标签的break语句终止外层语句。下面的程序BreakWithLabelDemo和前一个程序类似,但是它使用嵌套for循环在二维数组中搜索一个值。当找到这个值时,带标签break语句终止外层for循环(标签为“search”):

class BreakWithLabelDemo {

  public static void main(String[] args) {

    int[][] arrayOfInts = { { 32, 87, 3, 589 },

                                 { 12, 1076, 2000, 8 },

                                 { 622, 127, 77, 955 }

                               };

    int searchfor = 12;

    int i;

    int j = 0;

    boolean foundIt = false;

  search:

    for (i = 0; i < arrayOfInts.length; i++) {

       for (j = 0; j < arrayOfInts[i].length; j++) {

         if (arrayOfInts[i][j] == searchfor) {

           foundIt = true;

           break search;

         }

       }

    }

    if (foundIt) {

        System.out.println("Found " +

                               searchfor + " at " + i + ", " + j);

    } else {

        System.out.println(searchfor + " not in the array");

    }

  }

}

 

程序的输出为:

Found 12 at 1, 0

break语句终止带标签的语句;它不把控制流转到标签位置。控制流被转到紧跟在带标签(被终止的)语句后面的语句。

2. continue语句

continue语句跳过for、while或者do-while循环的当前迭代。无标签形式跳到最内层循环体的结尾,并且计算控制循环的布尔表达式。下面的程序ContinueDemo遍历一个字符串,计算字母“p”的出现次数。如果当前字母不是p,continue语句就跳过循环的剩余部分,然后处理下一个字符。如果是p,程序就递增字母计数器。

class ContinueDemo {

  public static void main(String[] args) {

    String searchMe = "peter piper picked a peck of " +

                           "pickled peppers";

    int max = searchMe.length();

    int numPs = 0;

    for (int i = 0; i < max; i++) {

      //interested only in p's

      if (searchMe.charAt(i) != 'p')

       continue;

      //process p's

      numPs++;

    }

    System.out.println("Found " + numPs +

                       " p's in the string.");

  }

}

这个程序的输出是:

Found 9 p's in the string.

为了更清楚地了解这种处理效果,可以删除continue语句,重新进行编译。再次运行程序时,计数器将是错误的,它指出找到了35个p,而不是9个。

带标签的continue语句跳过标有给定标签的外层循环的当前迭代。下面的示例程序ContinueWithLabelDemo使用嵌套的循环在一个字符串中搜索子字符串。这里需要两个嵌套的循环:一个迭代子字符串,另一个迭代正在被搜索的字符串。下面的程序ContinueWith- LabelDemo使用带标签的continue语句跳过外层循环的一次迭代。

class ContinueWithLabelDemo {

  public static void main(String[] args) {

    String searchMe = "Look for a substring in me";

    String substring = "sub";

    boolean foundIt = false;

    int max = searchMe.length() - substring.length();

  test:

    for (int i = 0; i <= max; i++) {

      int n = substring.length();

      int j = i;

      int k = 0;

      while (n-- != 0) {

      if (searchMe.charAt(j++) != substring.charAt(k++)) {

          continue test;

        }

      }

      foundIt = true;

      break test;

    }

    System.out.println(foundIt ? "Found it" :

                                       "Didn't find it");

  }

}

下面是这个程序的输出:

Found it

3. return语句

最后一个分支语句是return语句。return语句退出当前方法,控制流返回到调用这个方法的位置。return语句有两种形式:一种返回一个值,另一种不返回值。要返回一个值,只需将此值(或一个计算出此值的表达式)放在return关键字后面:

return  ++count;

return的返回值的数据类型必须匹配方法声明的返回值类型。当方法被声明为void时,使用return的不返回值形式:

return;

4.2.2节的第2小节将讨论编写方法所需的所有知识。

3.4.6  控制流语句小结

if-then是所有控制流语句中最基础的语句。它通知程序,只有特定检测结果为true时才执行特定代码段落。

if-then-else语句提供当if子句结果为false时的第二个执行路径。

与if-then和if-then-else语句不同,switch语句允许任意数量的可能执行路径。

当特定条件为true时,while和do-while语句持续执行一个语句块。

do-while和while之间的不同之处在于,do-while在循环的结尾处(而不是开始处)计算其表达式。因此,do块内的语句总会执行至少一次。

for语句提供对一个范围内的值进行迭代的紧凑方式。它有两种形式,其中一种用于遍历集合和数组。

问题和练习:控制流语句

问题

1.   Java编程语句支持的最基础的控制流语句是___语句。

2.   ___语句允许使用任意数量的可能执行路径。

3.   ___语句和while语句类似,但是在循环的___计算其表达式。

4.   如何使用for语句编写无限循环?

5.   如何使用while语句编写无限循环?

练习

1.   查看下面的代码段。

if (aNumber >= 0)

  if (aNumber == 0) System.out.println("first string");

else System.out.println("second string");

System.out.println("third string");

a. 如果aNumber为3,你认为代码将会输出什么结果?

b. 编写一个测试程序包含前面的代码段,使aNumber为3。这个程序的输出是什么?这是你预测的输出吗?解释输出为什么是这样;换句话说,代码段的控制流是怎样的?

c. 只使用空格和换行,重新格式化代码段,使控制流更易于理解。

d. 使用括号“{”和“}”,进一步使代码段更清楚明了。

答案

可以在以下位置找到“问题”和“练习”的答案:

tutorial/java/nutsandbolts/QandE/answers_flow.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值