2.4 控制流

控制流用于控制程序的执行顺序,包括条件语句、循环语句和选择语句等。

2.4.1 if条件语句

if条件语句的使用方式为:

     if(条件表达式)
        语句;

其含义是,如果条件表达式的值为true,则执行语句;否则,该语句不被执行。

例如:

     if(salary>10000)
       level="high";

当满足条件表达式,需要执行多条语句时,需要使用一对花括号将多条语句包含起来,例如:

     if(salary>10000){
       level="high";
       taxrate=0.006;
     }

上面的代码片段中如果不使用花括号,那么不论salary>10000是否成立,语句taxrate=0.006均会执行。而加上花括号后,只有在salary>10000成立时,才执行语句taxrate=0.006。

如果希望在if的条件表达式不满足时,执行特定的语句,则可以将else和if配对使用:

     if(salary>10000){
       level="high";
       taxrate=0.006;
     }else{
       level="low";
       taxrate=0.004;
     }

如果需要进行多次条件判断,可使用else if,例如:

     if(salary>10000){
       level="high";
       taxrate=0.006;
     }else if(salary>6000){
       level="medium";
       taxrate=0.005;
     }else{
       level="low";
       taxrate=0.004;
     }

if语句还可以嵌套使用。例如下面这段代码完成同样的功能,却是使用了嵌套的if语句:

     if(salary>10000){
       level="high";
       taxrate=0.006;
     }else{
        if(salary>6000){
           level="medium";
           taxrate=0.005;
       }else{
           level="low";
           taxrate=0.004;
       }
     }

2.4.2 for循环语句

for语句是一种常用的循环语句,其一般形式为:

     for(循环变量初始化;结束条件判断;修改循环变量值){
         语句;
         ...;
         语句;
     }

for语句的圆括号之间包含了3个部分,分别是循环变量初始化、结束条件判断和修改循环变量值,并且这3个部分用两个分号隔开。一对花括号所包括的内容称为循环体。

for语句的执行过程可以用图2.12来表示:执行for循环语句时,首先进入循环变量初始化①;然后立即进入循环结束条件判断②,结束条件判断的值为false时,结束循环,否则,执行循环体中的语句③;循环体中的语句执行完毕后,修改循环变量值④;再进行结束条件判断⑤,以确定是否需要再次执行循环体中的语句。

图2.12 for循环语句

注意:循环变量初始化只在首次进入时执行一次。

注意:每次执行循环体之前,都必须进行结束条件判断。

例2.2的作用是对1~100所有的整数求和。

例2.2 Sum.java

     public class Sum{
       public static void main(String []args){
         int sum=0;
         for(int i=1;i<=100;i++)
              sum=sum+i;
         System.out.println(sum);
         //i 不再有效
       }
     }

需要注意的是,在循环变量初始化中定义的变量(如例2.2中的i),只在循环体内有效,在循环体外是不能对其进行访问的。

for语句圆括号中的3个组成部分都是可选的,下面的for语句是一个无限循环:

     for ( ; ; ) {
         ...
     }

2.4.3 while/do while循环语句

while循环语句的使用方式为:

     while(条件表达式){
         语句;
         ...
         语句;
     }

同样,花括号之间的语句称为while循环体,如果没有花括号,那么最靠近while的一条语句作为循环体。每次执行循环体之前都需要进行条件表达式的计算,如果其值为true,那么执行循环体;否则,退出循环。

while循环常用在事前不能知道循环次数的场合。

例如:已知sum(k)=1+2+3+,…,+k,问k最小为什么值时能够使得sum(k)>2000。

例2.3求解了该问题。

例2.3 FindMinimalK.java

     public class FindMinimalK{
       public static void main(String []args){
         int sum=1;
         int k=1;
         while(sum<=2000){
           k++;
           sum=sum+k;
         }
         System.out.println("the minimal k="+k);
       }
     }

do while语句也常用在未知循环次数的场合,与while语句不同之处在于:while语句是先判断后执行,而do while是先执行后判断,也即do while的循环体至少执行一次。do while循环语句的使用方式为:

     do{
         语句;
         ...
         语句;
     } while(条件表达式);  //注意,这里要以分号结束

下面的代码片段使用do while循环语句来求解k的最小值:

     int sum=1;
     int k=1;
     do{
         k++;
         sum=sum+k;
     }while(sum<=2000);
     System.out.println("the minimal k="+k);

2.4.4 switch分支选择语句

在程序设计过程中,常常需要依据不同的条件选择执行不同的语句。当然,我们可以使用if-else语句,但是Java中也提供了switch语句可以完成同样的功能。例2.4的作用是将一个数值类型表示的月份转化为一个字符串描述的月份。

例2.4 MonthTranslator.java

     public class MonthTranslator{
       public static void main(String []args){
         String stringMonth="";
         for(int digitalMonth=1;digitalMonth<=13;digitalMonth++){
           switch (digitalMonth){
            case 1:  stringMonth="January";    break;
            case 2:  stringMonth="February";   break;
            case 3:  stringMonth="March";      break;
            case 4:  stringMonth="April";      break;
            case 5:  stringMonth="May";        break;
            case 6:  stringMonth="June";       break;
            case 7:  stringMonth="July";       break;
            case 8:  stringMonth="August";     break;
            case 9:  stringMonth="September";  break;
            case 10: stringMonth="October";    break;
            case 11: stringMonth="November";   break;
            case 12: stringMonth="December";   break;
            default: stringMonth="Error month";
           }
           System.out.println(digitalMonth+"  --->  "+stringMonth);
         }
       }
     }

运行后输出:

     1  --->  January
     2  --->  February
     3  --->  March
     4  --->  April
     5  --->  May
     6  --->  June
     7  --->  July
     8  --->  August
     9  --->  September
     10  --->  October
     11  --->  November
     12  --->  December
     13  --->  Error month

switch语句从与选择值相匹配的case标签处开始执行,一直执行到break处(执行break将跳出switch语句)或是switch的末尾。注意,switch只能接收整数类型的值。此外,当传递进来的值与所有的case标签均不匹配时,如果switch中含有default标签,将执行default标签后面的语句;如果default标签也不存在,那么switch中没有任何语句得到执行。

还有一点需要注意的就是:如果一个case子句后面不加break,那么当该子句执行完毕后,下一个case子句将被继续执行,直至遇到break或是switch语句结束。有的时候,这一性质可以被有效利用,例2.5用于求得某一月份所在的季度。

例2.5 QuarterTranslator.java

     public class QuarterTranslator{
       public static void main(String []args){
        String stringQuarter="";
         for(int digitalMonth=1;digitalMonth<=13;digitalMonth++){
           switch (digitalMonth){
              case 1:
              case 2:
              case 3:  stringQuarter="一季度"; break;
              case 4:
              case 5:
              case 6:  stringQuarter="二季度"; break;
              case 7:
              case 8:
              case 9:  stringQuarter="三季度"; break;
              case 10:
              case 11:
              case 12: stringQuarter="四季度"; break;
              default: stringQuarter="Error month";
           }
           System.out.println(digitalMonth+"  --->  "+stringQuarter);
         }
       }
     }

程序运行后输出:

     1  --->  一季度
     2  --->  一季度
     3  --->  一季度
     4  --->  二季度
     5  --->  二季度
     6  --->  二季度
     7  --->  三季度
     8  --->  三季度
     9  --->  三季度
     10  --->  四季度
     11  --->  四季度
     12  --->  四季度
     13  --->  Error month

Java 7增强了switch语句的功能,允许switch语句控制表达式是java.lang.String类型的变量或表达式——只能是java.lang.String类型,不能是StringBuffer或StringBuilder这两种字符串类型。

2.4.5 break、continue

在switch语句中,我们已经使用过break,其作用是跳出switch语句,将控制流转到紧跟在switch之后的语句。实际上,break更多的是用作跳出一个循环体,同样以求解2.4.3小节中k的最小值为例:

     int sum=1;
     int k=1;
     while(true){
       if(sum>2000)
         break;
       k++;
       sum=sum+k;
     }
     System.out.println("the minimal k="+k);

在该代码中,while是一个无限循环,当条件sum>2000满足时,break跳出循环,然后执行紧跟其后的打印语句。

需要注意的是,break只是跳出其所在的最内层循环体。例如,在下面的程序片段中,如果break执行,只是跳出while循环体,并不能跳出外层的for循环:

     for(...){
        while(...){
         if(...)  break;
         ...
       }
     }

如果需要直接跳出多层循环,可以使用带标签的break语句,例如:

     abc:
     for(...){
         while(...){
         if(...)  break abc;
         ...
       }
     }

其中abc是为for语句定义的标签。上面的代码中,当if的条件满足时,将直接跳出for循环体。

标签定义在一个有效的Java语句之前,格式如下:

     标签名: 语句;

注意:使用带标签的break语句时,标签必须定义在break之前。

与break语句不同,continue语句不跳出所在的循环体,而只是中断执行当前循环体的剩余部分,并进入下一轮循环。

例如,求解0~100所有偶数的和,sum=0+2+4+…+98+100。

例2.6求解了该问题。

例2.6 SumEven.java

     public class SumEven{
       public static void main(String []args){
         int sum=0;
         for(int i=0;i<=100;i++){
           if(i%2!=0)
             continue;
           sum=sum+i;
         }
         System.out.println("sum="+sum);
       }
     }

当i为奇数时,continue语句被执行。这时候,for循环体的剩余部分(sum=sum+i;)将不被执行,也就是不对奇数进行累加,而是转而执行for的循环变量值修改(i++),然后依据循环条件(i<=100),判断是否进入下一轮循环。