(翻译)《二》语言基础--控制流语句

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(翻译)《二》语言基础--控制流语句相关的知识,希望对你有一定的参考价值。

控制流语句

代码中的语句通常都是自上而下顺序执行。但是控制流语句打断执行的流程,利用决策、循环、分支,让你的程序有条件的执行代码的某一部分。本节描述java支持的决策语句(if-then,if-then-else,switch),循环语句(for,while,do-while),分支语句(break,continue,return)。

if-then和if-then-else语句

if-then是控制流语句中最基础的。它告诉你的程序执行某段代码,当某个特定的条件为真时。比如,Bicycle类会允许刹车降低自行车的速度,只有当自行车还在运动中。applyBrakes方法可能的实现如下:

void applyBrakes(){

  if(isMoving){

    currentSpeed--;

  }

}

如果条件为false(自行车没有移动),跳过if-then语句。

此外,如果只有一条语句,大括号是可选的。

void applyBrakes(){

  if(isMoving)

    currentSpeed--;

}

是否要省略大括号根据个人的风格。不过省略大括号使代码更脆弱。如果后面会在then分支中增加语句,一个常见的错误是忘记增加对应的大括号。编译器无法发现这类错误,你因此将会得到一个错误的结果。

if-then-else语句提供了另外的路径来执行,当if从句的结果是false。你可以在applyBrakes方法中使用if-then-else语句来执行一些动作,如果自行车在没有运动时使用刹车。本例中,将会打印一些错误信息说明自行车已经停下。

void applyBrakes(){

  if(isMoving){

    currentSpeed--;

  }else{

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

  }

}

下面程序,根据得分分配等级,大于90是A,大于80是B,大于70是C,大于60是D,其他是F。

class IfElsedemo{

  public static void main(String[] args){

    int testScore = 79;

    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 is " + grade);

  }

}

输出为C。

你也许注意到testScore的值满足混合语句中不止一条表达式:79>70;79>60。但是当一个条件满足,那么对应的语句就会执行(grade = ‘C‘),剩下的条件语句就不会执行了。

switch语句

不像if-then和if-then-else语句,switch语句可以有很多可以执行的路径。switch和byte、short、int、char基础数据类型工作。它也可以和枚举类型、String类、一些封装了基础数据类型的专门的类:Character、Byte、Short、Integer一起工作。

下面代码,声明一个int型变量month,其值表示月份;然后根据swich语句,打印月份。

public class SwitchDemo{

  public static void main(String[] args){

    int month = 8;

    String monthStr;

    switch(month){

      case 1:monthStr = "January";

          break;

      case 2:monthStr = "February";

          break;

      case 3:monthStr = "March";

          break;

      case 4:monthStr = "April";

          break;

      case 5:monthStr = "May";

          break;

      case 6:monthStr = "June";

          break;

      case 7:monthStr = "July";

          break;

      case 8:monthStr = "August";

          break;

      case 9:monthStr = "September";

          break;

      case 10:monthStr = "October";

          break;

      case 11:monthStr = "November";

          break;

      case 12:monthStr = "December";

          break;

      default:monthStr = "Invalid month";

          break;

    }

    System.out.println(monthStr);

  }

}

输出是August。

switch语句体被称为switch块。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");

}...

根据代码可读性和要测试的语句来决定使用switch语句还是if-then-else语句。if-then-else语句可以测试值的范围或条件,而switch语句只能根据一个整数、一个枚举值或一个String对象测试表达式。

另外一个有趣的地方是break语句。每一个break语句会终止一个switch块。控制流就继续执行跟在switch块后的第一条语句。break语句是必须的,如果没有它们,switch块中的语句会整个执行下去:匹配case标记后面的所有语句都会顺序执行,不管后面case的值是否匹配,直到碰到break语句。下面代码展示switch块从上而下整个执行,计算month对应月份和一年中其后的所有月份。

class SwitchFallThroughDemo{

  public static void main(String[] args){

    java.util.ArrayList<String> futureMonths = new java.util.ArrayList<String>();

    int month = 8;

    switch(month){

      case 1:futureMonths.add("January");

      case 2:futureMonths.add("February");

      case 3:futureMonths.add("March");

      case 4:futureMonths.add("April");

      case 5:futureMonths.add("May");

      case 6:futureMonths.add("June");

      case 7:futureMonths.add("July");

      case 8:futureMonths.add("August");

      case 9:futureMonths.add("September");

      case 10:futureMonths.add("October");

      case 11:futureMonths.add("November");

      case 12:futureMonths.add("December");

          break;

      default:break;

    }

    if(futureMonths.isEmpty()){

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

    }else{

      for(String month : futureMonths){

        System.out.print(month+" ");

      }

    }

  }

}

输出:August September October November December

技术上来说,最后一个break语句并不需要,因为流程已经流出switch语句。推荐使用break这样易于修改代码、减少错误可能性。default代码段处理所有没被case代码段处理的值。

下面例子展示一条语句有多个case标签。这个例子计算某月的天数。

class SwitchDemo2{

  public static void main(String[] args){

    int month = 2;

    int year = 2000;

    int numDays = 0;

    switch(month){

      case 1:caes 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

switch语句中使用字符串

java7及其以后,你可以在switch语句表达式中使用String对象。下面例子,通过字符串展示月数。

public class StringSwitchDemo{

  public static int getMonthNumber(String month){

    int num = 0;

    if(month == null)

      return num;

    switch(month.toLowCase()){

      case "january":

        num = 1;

        break;

      case "february":

        num = 2;

        break; 

      case "march":

        num = 3;

        break;

      case "april":

        num = 4;

        break;

      case "may":

        num = 5;

        break;

      case "june":

        num = 6;

        break;

      case "july":

        num = 7;

        break;

      case "august":

        num = 8;

        break;

      case "september":

        num = 9;

        break;

      case "october":

        num = 10;

        break;

      case "november":

        num = 11;

        break;

      case "december":

        num = 12;

        break;

      default:

        num = 0;

        break;

    }

    return num;

  }

  public static void main(String[] args){

    String month = "august";

    int num = StringSwitchDemo.getMonthNumber(month);

    if(num == 0){

      Sysem.out.println("invalid month");

    }else{

      System.out.println(num);

    }

  }

}

输出:8

switch表达式中的字符串与每个case标签表达式的比较就好像使用String.equals方法。为了忽略大小写,month参数转成小写(使用toLowCase方法),所有case标签的字符串都是小写。

注意,本例中检查switch表达式是否为null。确保switch表达式不为null,防止空指针异常。

while和do-while语句

 while语句会一直执行块中的语句当条件为真。如下:

while(expression){

  statement(s)

}

while语句计算表达式的值,表达式必须返回一个布尔值。如果表达式值为true,执行while块中的语句。while语句一直测试表达式和执行while块中的语句直到表达式的值为false。下面代码使用while语句打印1到10。

class WhileDemo{

  public static void main(Sring[] args){

    int count = 1;

    while(count < 11){

      System.out.println(count);

      count++;

    }

  }

}

你可以使用while语句实现一个无限循环:

while(true){

}

java同时提供了do-while语句,如下:

do{

  statement(s);

}while(expression);

while语句和do-while语句的区别在于do-while在循环的底部计算它的表达式,而while在顶部计算表达式。因此,do-while语句至少将其块执行一次。如下代码:

class DoWhileDemo{

  public static void main(String[] args){

    int count = 1;

    do{

      System.out.println(count);

      count++;

    }while(count<11);

  }

}

for语句

for语句提供了一个简洁的方法遍历一个范围之中的值。程序中一般用它来循环,因为在for语句中,它不停的重复直到满足某个条件。通常for语句如下:

for(initialization;termination;increment){

  statement(s);

}

使用这个版本的for语句时注意:

初始化表达式初始化这个循环,在循环开始时,执行一次;

当终止表达式计算得到false,循环终止;

循环的每次遍历之后,增加表达式都被执行,这里特别适用于增加或减少一个值;

下面程序使用通用的for语句来打印1到10:

class ForDemo{

  public static void main(String[] args){

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

      System.out.print(i+" ");

    }

  }

}

输出为:1 2 3 4 5 6 7 8 9 10

注意在初始化表达式中如何声明一个变量。这个变量的作用域从它的声明延续到块的结束,由for语句管理,所以变量可以被终止表达式和增加表达式使用。如果控制for语句的变量并不需要在循环外部使用,那么这个变量最好在初始化表达式中声明。变量名i、j、k通常用于for循环;在初始化表达式中声明它们,可以限制它们的生命周期和减少错误。

for语句中的三个表达式都是可选的,如下就定义了一个无限循环语句:

for(;;;){

}

for语句还有其他的形式,针对集合和数组的遍历。这些形式当作for语句的增强版,可以让你的循环更加紧凑和易读。如下,考虑下面这个数组,拥有数字1到10:

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

下面代码,使用增强版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.print(item+" ");

    }

  }

}

输出:1 2 3 4 5 6 7 8 9 10

我们推荐尽量使用增强版的for语句。

分支语句

 break语句有两种形式:有标记和无标记的。你在switch语句中已经见过无标记的。你也可以使用无标记的break来终止一个for、while、do-while循环,如下代码:

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(foundId){

      System.out.println("Found " + searchfor + " at index " + i);

    }else{

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

    }

  }

}

输出:Found 12 at index 4

程序在数组中寻找数字12。break语句,在数字找到时终止for循环,控制流跳到for循环后面的语句。

一个无标记的break语句终止最内层的switch、for、while、do-while语句,而一个有标记的break语句可以终止外层的循环语句。下面程序和上面程序类似,但是使用了嵌套的for循环在一个二维数组中找一个值。当值找到后,有标记的break终止外层的循环(标记"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(fountId){

      System.out.println("Found " + searchfor + " at index "+ i + " ,  " + j);

    }else{

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

    }

  }

}

输出:Found 12 at index 1, 0

break语句终止了标记语句;它不会把控制流交回给标记语句。控制流跳到标记语句的后面一条语句。

在for、while、do-while循环中使用continue语句跳过当前的遍历。无标签的形式跳到最内层循环的结尾,并计算控制循环的布尔表达式。下面程序对一个字符串,计算出现的字母p。当果当前字母不是p,continue语句跳过循环的剩余部分,并处理下一个字母。如果是p,计数加1。

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++){

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

        continue;

      numPs++;

    }

    System.out.println("found " + numPs + " p in the string");

  }

}

输出:found 9 p in the string

为了使效果更加清晰,试试去掉continue,重新执行。结果变成了35个p。

一个有标记的continue语句跳过当前的遍历,从标记的外层循环中。下面的例子使用嵌套循环在一个字符串中寻找子字符串。两个嵌套循环是需要的:一个循环遍历被寻找的字符串,一个遍历子字符串。下面代码用有标记的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 = 0; 

      int k = i;

      while(n-- !=  0){

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

          continue test;

        }

      }

      foundIt = true;

      break test;

    }

    System.out.println(foundIt ? "found it" : "not found it");

  }

}

输出:found it

最后一条分支语句是return语句。return语句从当前方法中退出,控制流返回到该方法调用的位置。return语句有两种形式:一种返回一个值,一种不返回值。返回值(或者是一个表达式计算出一个值)只需要把值跟在return的后面。

return ++count;

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

return

后面会讲到方法。

控制流语句总结

if-then语句是所有控制流语句中最常用的。它告诉你的程序去执行某段代码当你的条件计算为true时。if-then-else语句提供了第二条执行路径当if分句计算为false。不像if-then和if-then-else,switch语句允许任意数量的执行路径。当某个条件为真时,while和do-while语句一直执行一块语句。while和do-while的区别是do-while在循环的底部计算它的表达式,而不是顶部。因此,do-while中的块语句至少执行一遍。for语句提供简洁的方法遍历一个范围内的值。它有两个形式,其中一个是针对集合和数组的。

 

以上是关于(翻译)《二》语言基础--控制流语句的主要内容,如果未能解决你的问题,请参考以下文章

编译原理—中间代码生成布尔表达式翻译短路计算控制流语句翻译条件语句循环语句

(翻译)《二》语言基础--表达式语句块

go语言学习笔记 — 基础 — 控制流:break, continue循环控制语句

C语言流控制命令的总结

java基础-控制流语句

java基础-控制流程语句