JavaSE0005_Java流程控制语句

Java SE 第四节

 

流程控制语句

 FlowControl Statement

数学上证明顺序结构、分支结构、循环结构是一个完备集。

 

1. 条件运算符(三元表达式),其形式为:

type d = a ? b : c; 具体化形式为:int d = 2 < 1 ? 3 : 4;

如果 a 为真,d = b ; 如果 a 为假, d = c ;

2. 轻量级的文本编辑器:UltraEdit、Editplus、vi、vim、gvim

3. 流程控制语句if的用法为:

第一种形式:

if(布尔表达式)

{

//待执行的代码

}

第二种形式:

if(布尔表达式)

{

//待执行的代码

}

else

{

//待执行的代码

}

第三种形式:

if(布尔表达式)

{

//待执行的代码

}

else if(布尔表达式)

{

//待执行的代码

}

else if(布尔表达式)

{

//待执行的代码

}

else

{

//待执行的代码

}

4. switch语句,使用形式为:

switch(变量) //此处的变量类型就目前所学内容来看,只能为4种

类型:byte,short, int, char。

{

case 常量1:

//待执行的代码

break;

case 常量2:

//待执行的代码

break;

case 常量3:

//待执行的代码

break;

default:

//待执行的代码

}

虽然case语句中的break是可选的,但在绝大多数情况下,如果没有break,程序的逻辑就会发生错误,因此,通常情况下都需要加上break。

 

If 语句可以代替switch,但后者不能代替前者,因为后者的变量类型受到限制。

 

5. Java中的循环控制语句一共有3种,分别是while,do… while以及for循环。

6. while循环,形式为:

while(布尔表达式)

{

//待执行的代码

}

7. do…while循环,新式为:

do

{

//待执行的代码

}

while(布尔表达式);

4. while与do…while之间的区别:如果布尔表达式的第一次判断就为false,那么while循环一次也不执行;do…while循环则会执行一次。如果布尔表达式第一次判断为true,那么while循环与do…while循环等价。

5. for循环(使用最多的一种循环),形式为:

for(变量初始化; 条件判断; 步进)

{

//待执行的代码

}

for循环的执行过程:

1)执行变量初始化。

2)执行条件判断。如果条件判断结果为假,那么退出for循环,开

始执行循环后面的代码;如果条件判断为真,执行for循环里面的代

码。

3)执行步进。

4)重复步骤2。

For循环初始化可以不写,但是分号必须保留,用以判断对应的是哪个项目

 

1. break语句:经常用在循环语句中,用于跳出整个循环,执行循

环后面的代码。

2. continue语句:经常用在循环语句中,用于跳出当前的这个循环

(或者是跳出本次循环),开始下一次循环的执行。

3. break与continue可以搭配标签使用,在实际开发中,根本没有人会将break与continue搭配标签来使用。


Java 分支语句


程序运行过程中,需要对运行的流程顺序做控制。基本上程序的执行过程分三种:

 

1.顺序执行

   从开始到结束,依次运行代码,直至全部运行结束。

 

2.分支语句

   在执行过程中,根据某些情况条件,只执行其中一部分语句代码

 

3.循环执行

   在执行过程中,重复的执行某些语句代码。

 

 

我们先前做的那些示例练习,大部分都是顺序执行代码,这个是很自然熟悉的,也不需要特别的练习了,现在我们先看看分支语言如何来实现。

 

在现实世界中,很多这样的情况:如果今天下雨,就呆在家里看DVD,否则的话就出去打球。这样的选择题多得很。编程语言都来模拟这个逻辑,实现了条件分支i情况处理。

 

分支语句实现程序流程控制的功能 ,即根据一定的条件有选择地执行或跳过特定的语句。

 

Java分支语句分为两种:


if-else 语句:一种控制程序流程的最基本的方法,else子句可有可无;


switch 语句:另一种效率程序流程控制语句,当必须在程序中检测一个整型表达式的多个值时将会用到它。


下面我们首先来看if语句。

 

条件语句是最常用的一种分支语句,它的基本格式是:

  if ( boolean expression ){
   statement or block;
  }


或者:


  if ( boolean expression ){
   statement or block;
  } else if  (boolean expression) {
   statement or block;
  } else {
   statement or block;
  }


在if后面的条件语句中,必须是一个可以转换成boolean 的表达式,这个表达式需要用括号括起来。


下面来看一个示例代码。

 

public class IfTest {
 /**
  * @param None
  * @return Nothing
  */
 public static void main(String args[]) {
  int i;
  i = 13;
  System.out.println("*************************************");
  if (i < 50) {
   System.out.println("* The input number is less than 50! *");
  } else if (i == 50) {
   System.out.println("* The Input number is equal to 50!  *");
  } else {
   System.out.println("*The input number is greater than 50*");
  }
  System.out.println("*************************************");
 }
}


这个类非常简单,在它的main()方法中,定义了一个int类型的变量i,然后给i赋了一个值13。

 

在if分支语句中,根据这个i变量的取值向控制台打印不同的信息:如果i小于50,将执行分支i<50后的代码块,它向控制台输出“The Input number is less than 50!”;如果i等于50,将执行分支i==50后的代码块;如果i大于50,将执行分支i>50后的代码块。

 

在这个例子中,因为i的值等于13,它小于50,所以,将执行分支i<50代码块中的语句,它将向控制台输出如下的信息:


*************************************
* The input number is less than 50! *
*************************************


我们可以修改程序中的i的值,让它大于或者等于50,然后重新编译执行,看看输出的信息是否发生了变化。


在Java中,能够进行分支控制的语句,除了if以外,还有switch。

 

一个switch语句由一个控制表达式和一个由case标记描述的语句块组成。

 

和if不同,switch后面的控制表达式求出的值应该是整型而不是boolean类型,这点在初学时要尤为注意。从控制表达式的数据类型可以看出,if语句应用范围应该更为广泛常见,因为大部分的条件分值控制都是使用真假布尔运算来判断的,这在现实世界中也极为常见,比如前面的例子,今天的计划安排,是由天气情况来决定的,下雨,不下雨,很显然就是下雨情况的真假布尔判断。

 

可以这么说,switch能做的事情,if完全可以做到,你在写Java代码的时候,即使你不知道switch,也可以完成代码的编写。那么switch出现的意义是什么呢?

 

先别急,我们先把switch的用法搞清楚了。 

 

switch语句对控制表达式求得的值,决定了哪一个case分支将被执行。每一个case都用唯一的常量表达式或常量来标示,用于控制这个case是否必须被执行。

 

程序将执行到那些表达式值与控制表达式的值相匹配的case分支中。如果不存在这样的匹配,则将执行default后面的代码块。如果没有default标记(并不推荐这样做),则控制被传递到switch块后的第一条语句,也就是退出了switch块。


控制表达式必须是可以转化为byte、short、char或int类型的值的表达式。实际上switch的控制表达式接收是int类型的值,之所以能接收byte、short、char型的值,用前面提到的数据类型隐式转换就可以明白了,是Java根据实际情况,岁这几种数据类型做了类型转换,因为long不允许隐式转化为int,所以不能直接使用long型的数据值。

 

注意在每一个case标记的代码块中,最后都有一个break语句。这条语句具有重大的作用,如果没有这条语句,当与case分支相连续的代码块执行完毕后,将会继续运行与下一个case 分支相联系的代码块。一般情况下这与我们的初衷不符,但是有的情况下,也可以结合这种特性,简化我们的代码。看下面的这个示例: 

 

public class SwitchCase {
 public static void main(String args[]) {
  int n = 2;
  int result;
  switch (n + 1) {
  case 1: {
   System.out.println("Block A");
   result = n;
   break;
  }
  case 2: {
   System.out.println("Block B");
   result = n * n;
   break;
  }
  case 3: {
   System.out.println("Block C");
   result = n * n * n;
   break;
  }
  case 4: {
   System.out.println("Block D");
   result = n % 4;
   break;
  }
  default:
   result = 0;
  }
  System.out.println("n=" + n + " result=" + result);
 }
}


在这个例子中,定义了一个整形变量n,并给它赋值2,在switch中,根据表达式“n+1”得到的整数值执行不同的代码块:1、2、3、4都定义了各自的执行方式,如果不是这些数,则将执行default中的语句,将变量“result”赋值为0。


编译并运行上面的程序,将得到如下的结果:
Block C
n=2 result=8


从执行结果中可以很清楚的看出,case 3后面的代码被执行了,它将result赋值为n*n*n运算后得到的值,也就是为2*2*2的值。


如果一个case分支打算执行与紧随其后的case语句相同的动作,那么在这个case分支中可以不用写任何的代码:
 switch(expr){
 case 0:
 case 1:
  statements;
  break;
 case 2:
  … …
在这里,case 0分支会执行和case 1分支一样的操作。

 

case相对于switch处理逻辑的入口,上面的这个示例的写法,相当于把0与1的这两个入口合并为一个逻辑了。在实际的编码情况中,这点也很常见,比如大月与小月的判断,大家可以试着写写这个判断逻辑。

 

最后总的来说,switch可以看做是一种特殊情况下的if语句,用来编写更加清晰,简明的分支语句,如果你的逻辑分支判断都是等值判断,并且判断的条件多于3个以上的话,switch就是更好的选择了。

 

if语句可以不但的嵌套,在else之后,可以继续跟进if-else语句,来完成多个复合的布尔判断分支语句。就拿遥控器操作来说,如果你按1键,进入一频道,按2键,进入2频道,按音量增大键,进行音量调节增大操作,以此类推。如果那if来写,就会出现n个if-else嵌套,无论编写,还是阅读,都难于处理维护。

 

比如:

 

if(key==1){

//操作

}else if(key==2){

//操作

}else if(key==3){

//操作

}....

else{

//操作

}

 

现在代码量不大,看起来还可以接受。那么如果其中的注释操作,换成真正的操作的话,这段代码量就很可观了,到时候在一对if-else中间“遨游”,你就会对这种写法痛恨不已了。

 

如果换成switch呢? 

 

switch(key){

  case 1:

  case 2:

  case 3:

  ...

  default:

 

}

 

当然不要忘了break处理,这样看起来,即使增加了处理逻辑代码,也比if-else看起来舒服多了吧。重点是代码的可读性和可维护性,这点在实际项目中是非常重要的。


循环语句的功能是在循环条件满足的情况下,反复执行一段代码,直到不再满足循环条件为止。

 

这个类型的工作恐怕是现在计算机最适合去做的事情之一了。无论哪个人在勤恳,重复做同样一件事情总是会新生倦怠的,这是谁也避免不了的。并且还不能保证重复做得每一次都是保证同样的质量和结果。

 

但是计算机就不同了,或者说机器就是不同了,它们非常适合做这类重复性的活动。

 

循环语句一般由下述四部分组成:
初始化部分(init_statement):一条或多条语句,用来做一些初始化工作,例如设置计数器初值等;

循环条件部分(test_exp):这是一个boolean类型的表达式,根据它的值来判断是否继续进行下一次循环;
循环体部分(body_statement):将被循环执行的目标代码,可以是一条语句,也可以是一个语句块;
迭代部分(alter_statement):在一次循环结束后,下一次循环开始前执行的语句,通常用于修改循环计数器的值。


循环语句使语句或块的执行得以重复进行。

 

Java编程语言支持三种循环构造类型:for, while和do while。三种循环结构均通过一个条件表达式来控制。

 

在while()和for()结构中,条件判断均先于语句块执行,所以,有可能语句块一次也不执行。


在do…while()中,语句块先于条件判断,所以,语句块至少执行一次。

 

这里先来看for循环的使用。

 

for语句的基本格式如下:
  for ( init_expr ; boolean test_expr ; alter_expr){
   statement or block;
  }


其中:init_expr表示初始化代码,而test_expr是用于条件判断的表达式,如果表达式的值为true,则执行后面的语句,接下来进行后面的步进代码alter_expr。如果条件判断表达式test_expr第一次求值就为false,那么for循环不会进行任何的迭代,后面的statement也不会进行任何的操作。


程序执行遇到for语句时,首先执行初始化部分(init_statement)的语句,然后计算循环条件表达式test_exp的值,如为true,则执行循环体部分的语句(body_statement),否则结束循环。


一次循环结束后,下一次循环开始前,执行迭代部分的语句(alter_statement),然后判断循环条件表达式test_exp的值,决定是否进行下一次循环。


请看下面这个for循环的例子:
 int result = 1;
 for (int k = 5;k>1;k--) {
  result = result * k;
 }


上面这个程序片断的作用是实现一个简单的阶乘运算:n*(n-1)*(n-2)*…*1,在这里,n的值为5,因此,它运算的结果是5*(5-1)*(5-2)*(5-3)*(5-4)=5*4*3*2*1=120。

 

上面的例子中,init_expr只有一个初始化的值,条件判断表达式也只有一个条件,步进代码也是每次递减一个数字。但是,其实Java允许在for语句的循环控制的各个部分放置任何表达式,如下例:
 for(int b = 0,s = 0,p = 0;(b<10)&&(s<4)&&(p<10);p++){
  //代码块
  //更新b和s 的值
 }


在这个例子中,初始化的变量有三个,但是,只能有一个声明语句,所以,如果需要在初始化表达式init_expr中声明多个变量,那么这些变量必须是同一种数据类型的。


for循环并没有限制在它的for语句的每一部分都必须提供一个表达式,这三个部分其实都可以为空,此时,是一个无限的循环。这在语法上是没有错误的,只是这种循环在实际应用中会引起很多的问题,我们应该避免这种会引起无限循环的for语句。

下面来看一个例子,来了解一下for语句中各部分为空时的控制情况:
 int sum=0;
 //注意看这个for语句,它的步进部分是空的
 for (int i=1;i<=n;){
  sum=sum+i;
  //将步进放到了for程序块中
  i++;
 }


注意这个for语句,它的步进部分是空的,我们将这个步进运算放到了程序块中。

 

一个无限for循环的例子如下:
 for(;;){
  //程序块
 }


这种情况一般是要避免的,我们不应该让程序出现这种无限循环的情况。

在for语句内定义的变量,它的作用范围仅限于for语句块、表达式以及for子句的语句部分。在for循环终止后,它们将不可被访问。如果需要在for循环外部使用循环计数器的值,可以将这个变量定义在for循环体外,如下:
 int k;
 for(k = 0;k<10;k++){
  //statements
 }


 //此时可以再使用变量k


另外,如果变量定义在for循环体内,则在另外一个循环体中还可以使用相同的变量名称,如下:
 for(int k=0;k<10;k++) {
  … …
 }
 
 for(int k = 100;k>0;k--) {
  … …
 }


上面的代码段是合法的。

 

 

while循环语句的格式:
 init_statement
 while ( boolean_expr ){
  statement or block;
  alter_expr;
 }


while语句首先测试boolean_expr表达式的值,如果为true,则运行代码块中的程序,并且一般需要进行迭代运算,以改变boolean_expr表达式中的变量的值,直到表达式中的值变为false。


如果刚开始条件表达式就为false,则while循环永远也不会被执行。


来看一个while循环的例子:
 … …
 //while循环
 int result1=0;
 int result2=0;
 //初始化一个变量
 int i=1;
 //利用这个变量构成一个条件表达式
 while(i<=10) {
  result1=result1+i;
  //将i加1
  i=i+1;
 }
 System.out.println("After the While Loop,the result1 is:"+result1);
 … …


for循环和while循环是等价的,我们可以将如下的for循环:
for(init_expr;test_expr;alter_expr){
 statements;
}


改写成如下的while循环方式:
init_expr;
while(test_expr){
 statements;
 alter_expr;
}

这两种方式是完全可以相互替换的。for循环和其他两个循环控制语句不同的地方在于,它可以在控制表达式中定义变量,而while/do…while不能这样做。


do…while循环语句的格式如下:
[init_expr]
do{
   body_statement;
  [alter_expr;]
}while( test_expr);


do…while循环类似于while循环,在while后面也得跟一个boolean类型的表达式。do…while循环首先执行里面的代码段,然后再根据test_expr判断是否为true,如果为true,则返回到do语句来执行,否则,退出整个循环。

 

因为do…while循环是先运行里面的代码块,然后再判断条件,所以,do…while循环至少会执行一次,这是do…while循环和while、for 循环最大的区别所在。


我们来看下面这个例子:
 int result1=0;
 int result2=0;
 int j=1;
 do {
  result2=result2+j;
  j=j+1;
 }while(j<=10);
 System.out.println("After the Do Loop,the result2 is:"+result2);


比较一下这个例子和上面while的例子,这两个例子中的test_expr都是一样的,但是,它们运行后得到的结果也是一样的。

 

在while循环中,得出的运算结果是55,而do…while得出的结果也是55。

 

但是,如果将各自的条件改成(i<=0)和(j<=0),则do…while循环将会返回一个1的结果,而while循环却只能返回一个0的结果,这就是因为do…while是“先执行,后判断”,而while却是“先判断,后执行”。


使用break语句可以终止switch语句和终止循环的子语句块,甚至是普通的程序块。关于如何终止switch语句,前面已经说过。这里主要说明如何来控制循环语句的执行。

 

1.break语句

 

在循环中,经常的,我们需要在某种条件出现时,强行终止循环的运行,而不是等到循环的判断条件为false时,这个时候,可以通过break来完成这个功能。


下面来看一个break的例子:
 int sum1 = 0,n=10;
 for (int i=1;i<=n;i++){
  sum1=sum1+i;
  if(i%2==0)break;
 }


这个例子中,如果i能够被2整除,就跳出这个for循环。

 

因此,实际上,这个for循环只能循环两次,得到的sum1的值是3。

 

对于很多有C++或其他编程经验的读者,可能对于goto语句不会陌生,也可能曾经深受其困。在Java中,goto语句虽然是保留字,但并没有使用它。但在Java里也有类似goto的功能,这个功能和break以及continue结合。

 

在本质上而言,它和goto语句的跳跃是不同的,它是一种循环中断的方式而已。它和goto语句的相同点在于,它们都使用了标签(label)。


所谓标签(label),就是后面跟了一个冒号“:”的标识符,如:
oneLabel:


从语法上看,在Java程序中,标签可以放在任意的地方,但是,一般而言,标签只有放在循环语句之前,才能真正起到应有的作用,如下:
LableOne:
循环
{
… …
}


我们来看一个用在嵌套循环中的和标签结合的break例子:
  outer:
  for(int i = 0;i<10;i++) {
   System.out.println("Outer loop:");
   inner:
    while(true) {
     int k = System.in.read();
     System.out.println("Inner Loop:"+k);
     if(k=='b') break inner;
     if(k=='q') break outer;
    }
  }

在这个例子中,从控制台接收一个输入,如果输入b,则退出内层的while循环,如果输入q则退出外层的循环(也就是终止整个循环)。

 

另外,如果需要终止普通的语句块(既不是switch也不是循环语句),则必须使用标签:


Label1:
 {
 Label2:
  {
  Lable 3:
   {
   …. …
   }
  }
 }

 

2.continue语句

 

continue语句用来略过循环中剩下的语句,重新开始新的循环,这和break语句的完全跳出循环是不一样的。


continue 仅仅出现在while/do…while/for语句的子语句块中。


也可以使用和标签结合的方式来选择需要终止的嵌套循环的层级。


下面来看一个例子:
 int sum1=0;                    
 int sum2=0;                    
 //Continue                     
 for (int j=1;j<=10;j++)  {                              
  if(j%2==0)continue;    
  sum2=sum2+j;           
 }                              
 System.out.println(sum2); 


在这个例子中,如果在j可以被2整除,则不进行后面的相加操作,而重新返回到循环的开头

 

因此,它运算后的值为:25。完整的代码请参考示例4-11中的BreakAndContinue.java中的Continue部分。

在上一小节介绍break的时候,我们就提到过,在continue中也可以使用标签。

 

现在我们来看一个continue和标签结合的例子:

源文件:ContinueWithLabelDemo.java
public class ContinueWithLabelDemo {
 public static void main(String[] args) {
  String searchMe = "Look for a substring in me";
  String substring = "subs";
  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++)) {
     // 跳出的本次循环是for循环,而不是while循环
     continue test;
    }
   }
   foundIt = true;
   // 跳出整个循环
   break test;
  }
  System.out.println(foundIt ? "Found it" : "Didn't find it");
 }
}


这个程序的作用是从字符串searchMe中搜索指定的子串substring,从要搜索的字符串substring(假设为“subs”)第一个子符开始去匹配searchMe的第一个字符,如果第一个字符都不匹配,就不用再比较第二个字符了(利用continue)。

 

如果第一个字符匹配,则比较第二个字符,如果第二个字符不匹配,则不用再往下比较,否则,往下比较第三个字符,依次类推。

 

如果找到完全匹配的子字符串,则退出整个循环(break)并且返回true。然后根据是否返回true打印出“Found it”或“Didn’t find it”。


如果substring的值为“subs”(如程序中所示),则会在控制台上打印出“Found it”,如果substring的值为“abc”,则会打印出“Didn’t find it”。




 

你可能感兴趣的:(JavaSE)