Java 程序设计基础之流程控制

关于 Java 程序设计语言的 基础语法 部分,前面我们已经详细了解过了 Java 中的字面值,变(常)量,数据类型以及操作符,这里我们来看 Java 基础语法的另一个重要组成部分——Java 中的流程控制语句,它决定程序要进入什么流程,即“做什么”以及“怎么做等。

流程控制结构

从结构化程序设计角度出发,编程语言一般会有 3 种结构:

  • 顺序结构
  • 分支结构
  • 循环结构

若是在程序中没有给出特别的执行流程控制,系统则默认自上而下一行一行地执行该程序,这类程序的结构就称为顺序结构

但事实上,现实事物的发展往往不会遵循早就设想好的轨迹进行,此时需要引入:分支结构,循环结构


分支结构

Java 支持两种选择语句:

  1. if 语句:使用 布尔表达式或布尔值 作为分支条件,来进行程序执行分支控制
  2. switch 语句:用于对多个 整型值、字符串值 进行匹配,从而实现程序执行分支控制。

下面会分别对上述的两种选择(分支)语句进行解读:


if 语句

1 –> if 结构

if 语句的最简语法格式如下,表示:“如果条件表达式为 true,就执行语句块”。

1
2
3
if (条件表达式) {
语句块;
}

if 条件语句的运行流程如下:

实例:

1
2
3
4
5
6
7
8
9
10
public class HelloWorld {
public static void main(String[] args) {

boolean b = true;
if(b){ // 如果成立就打印:yes
System.out.println("yes");
}

}
}

–> 多表达式与一个表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class HelloWorld {
public static void main(String[] args) {

boolean b = false;
// 如果有多个表达式,必须用大括弧包括起来
if(b){
System.out.println("yes1");
System.out.println("yes2");
System.out.println("yes3");
}

// 否则表达式2 3, 无论 b 是否为 true 都会执行
if(b)
System.out.println("yes1");
System.out.println("yes2");
System.out.println("yes3");

// 如果只有一个表达式可以不用写括弧,看上去会简约一些(但语法规范不推荐)
if(b){
System.out.println("yes1");
}

if(b)
System.out.println("yes1");

}
}

2 –> if-else 结构

if-else 结构语法格式如下,表示:“如果条件(表达式)正确则执行 –> 语句块1,否则执行 –> 语句块2”。

1
2
3
4
5
if (表达式) {
语句块1;
} else {
语句块2;
}

if-else 结构的运行流程如下:

实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class HelloWorld {
public static void main(String[] args) {

boolean b = false;

if (b){
System.out.println("yes");
}
else{
System.out.println("no");
}
}
}

3 –> 多条件 if-else-if 结构

if-else-if 结构是多条件判断,语法格式如下:

1
2
3
4
5
6
7
8
9
10
if(表达式1) {
语句块1;
} else if(表达式2) {
语句块2;
...
} else if(表达式n) {
语句块n;
} else {
语句块n+1;
}

表现为:依次判断表达式的值,当某个分支的条件表达式的值为 true 时,则执行该分支对应的语句块,然后跳到整个 if 语句之外继续执行程序。如果所有的表达式均为 false,则执行语句块 n+1,然后继续执行后续程序。

if-else-if 结构的运行流程如下:

实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class HelloWorld {
public static void main(String[] args) {

// 如果只使用 if,会执行 4 次判断
int i = 2;
if (i==1)
System.out.println(1);
if (i==2)
System.out.println(2);
if (i==3)
System.out.println(3);
if (i==4)
System.out.println(4);

// 如果 i == 2 时成立,则后续判断均不再执行
if (i==1)
System.out.println(1);
else if (i==2)
System.out.println(2);
else if (i==3)
System.out.println(3);
else if (i==4)
System.out.println(4);

}
}

4 –> if 嵌套结构

if 条件结构里嵌套另一个 if 结构。同样,if…else 结构语句和 if…else if 结构语句中也可以嵌套另一个 if 结构的语句,以完成更深层次的判断(一般不要超过 3 层)。

嵌套 if 的语法格式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
if(表达式1) {
if(表达式2) {
语句块1;
} else {
语句块2;
}
} else {
if(表达式3) {
语句块3;
} else if(表达式4) {
语句块4;
} else {
if(表达式n) {
语句块n;
} else {
语句块n+1;
}
}
}

switch 语句

switch 语句是 Java 中的多路分支语句,提供了一种基于一个表达式的值来使程序执行不同部分的简单方法。

switch 提供了一个比一系列 if-else-if 语句更好的选择。

switch 语句的基本语法形式如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
switch(表达式) {
case1:
语句块1;
break;
case2:
语句块2;
break;

case 值n:
语句块n;
break;
default:
语句块n+1;
break;
}

switch 语句的执行过程如下:表达式的值与每个 case 语句中的常量作比较。如果发现了一个与之相匹配的,则执行该 case 语句后的代码。如果没有一个 case 常量与表达式的值相匹配,则执行 default 语句。

default 语句是可选的。

如果没有相匹配的 case 语句,也没有 default 语句,则什么也不执行。

注意:重复的 case 值是不允许的。

=================================================

使用注意:

  • switch 关键字后面小括号里的值:要放一个整型变量或字符型变量;表达式必须为 byte,short,int,char类型;
  • case 关键字后的值,可以是:类型为 char、byte、 short 或 int 的常量表达式;enum 常量;或字符串字面量;
  • break:一般语句块后均需要加 break;如果在 case 分支语句的末尾没有 break 语句,那么就会接着执行下一个 case 分支语句。这种情况相当危险,常常会引发错误。
  • default:表示“默认”,即其他情况都不满足;default 块和 case 块的先后顺序可以变动,不会影响程序执行结果。通常,default 块放在末尾,也可以省略不写。
  • switch 语句中也支持嵌套,但一般不这么用
  • if 语句可计算任何类型的布尔表达式。也就是 switch 语句只能寻找 case 常量间某个值与表达式的值相匹配。

循环结构

所有流行的编程语言中都有循环语句。Java 中采用的循环语句与C语言中的循环语句相似,主要有:

  • while
  • do-while
  • for

Java 5 之后,还推出了 for-each 循环语句。它是专门为数组、集合遍历而设计的。但 for-each 并不是一个关键字。

while 语句

while 语句是 Java 最基本的循环语句,是一种先判断的循环结构。while 循环语句的语法结构如下:

1
2
3
while(条件表达式) {
语句块;
}

其中语句块中的代码可以是一条或者多条语句,而条件表达式是一个有效的 boolean 表达式,它决定了是否执行循环体。当条件表达式的值为 true 时,就执行大括号中的语句块。

循环语句的执行流程如下:

实例:

1
2
3
4
5
6
7
8
9
10
11
public class HelloWorld {
public static void main(String[] args) {

// 打印 0~4
int i = 0;
while(i<5){
System.out.println(i);
i++; // 控制循环结束
}
}
}

do…while语句

如果 while 循环一开始条件表达式就是假的,那么循环体就根本不被执行。然而,有时需要在开始时条件表达式即使是假的情况下,while 循环至少也要执行一次。

do-while 循环语句的特点是先执行循环体(循环至少也要执行一次),然后判断循环条件是否成立,成立后继续执行。

do-while 语句的语法格式如下:

1
2
3
do {
语句块;
}while(条件表达式);

do-while 循环语句执行流程如下:

实例(图书列表中保存了 50 条信息,现在需要让它每行显示 10 条,分 5 行进行显示):

1
2
3
4
5
6
7
8
9
10
public static void main(String[] args) {
int bookIndex = 1;
do {
System.out.print(bookIndex+"\t");
if(bookIndex%10 == 0) {
System.out.println();
}
bookIndex++;
}while(bookIndex<51);
}

for 语句

for 循环,和 while 循环一样,只是表达方式不一样。

for 语句语法格式如下所示:

1
2
3
for(条件表达式1;条件表达式2;条件表达式3) {
语句块;
}

for 关键字后面括号中的 3 个条件表达式必须用 “;” 隔开。

for 循环中 3 个表达式的含义:

表达式 形式 功能 举例
条件表达式 1 赋值语句 循环结构的初始部分,为循环变量赋初值 int i=1
条件表达式 2 条件语句 循环结构的循环条件 i>40
条件表达式 3 迭代语句,通常使用 ++ 或 – 运算符 循环结构的迭代部分,通常用来修改循环 变量的值 i++
1
2
3
4
5
6
7
8
9
public static void main(String[] args) {

for (int bookIndex = 1;bookIndex<51;bookIndex++){
System.out.print(bookIndex+"\t");
if(bookIndex%10 == 0) {
System.out.println();
}
}
}

==================================================

特别:

for 语句中初始化、循环条件以及迭代部分都可以为空语句(但分号不能省略),三者均为空的时候,相当于一个无限循环。但无论缺少哪部分条件表达式,都可以在程序的其他位置补充,从而保持 for 循环语句的完整性,使循环正常进行。

1 –> 条件表达式 1 为空

例如,使用 for 语句的这种形式计算 1~100 所有奇数的和。

1
2
3
4
5
6
7
8
9
public static void main(String[] args) {
int result = 0;
int number = 1; // 相当于for语句的第1个表达式
for (; number < 101; number++) {
if (number % 2 != 0) // 如果不能整除2,说明是奇数,则进行累加
result += number;
}
System.out.print("100 以内所有奇数和为:" + result);
}

2 –> 条件表达式 2 为空

当 for 语句中条件表达式 2 为空时,将没有循环的终止条件。为了使循环达到某种条件时退出,需要在语句块中进行逻辑判断,并使用 break 语句来跳出循环,否则将产生死循环。

同样是计算 1~100 所有奇数的和,使用这种方式的代码如下。

1
2
3
4
5
6
7
8
9
10
public static void main(String[] args) {
int result = 0;
for (int number = 1;; number++) {
if (number > 100)
break; // 相当于for语句的表达式2,满足时就退出for循环
if (number % 2 != 0) // 如果不能整除2,说明是奇数,则进行累加
result += number;
}
System.out.print("100 以内所有奇数和为:" + result);
}

3 –> 条件表达式 3 为空

当 for 语言中条件表达式 3 为空时,也就没有设置控制变量的表达式,即每次循环之后无法改变变量的值,此时也无法保证循环正常结束。

同样是计算1~100 所有奇数的和,使用这种方式的代码如下:

1
2
3
4
5
6
7
8
9
public static void main(String[] args) {
int result = 0;
for (int number = 1; number < 101;) {
if (number % 2 != 0) // 如果不能整除2,说明是奇数,则进行累加
result += number;
number++; // 相当于for语句的条件表达式3,每次递增1
}
System.out.print("100 以内所有奇数和为:" + result);
}

4 –> 3 个条件表达式都为空

事实上,在 for 循环语句中,无论缺少哪部分条件表达式,都可以在程序的其他位置补充,从而保持 for 循环语句的完整性,使循环正常进行。

但是,对于这种情况,读者在使用时应该尽量避免。

例如,计算 1~100 所有奇数的和,使用这种方式的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
public static void main(String[] args) {
int result = 0;
int number = 1; // 相当于for语句的条件表达式1
for (;;) {
if (number > 100)
break; // 相当于for语句的条件表达式2
if (number % 2 != 0) // 如果不能整除2,说明是奇数,则进行累加
result += number;
number++; // 相当于for语句的条件表达式3
}
System.out.print("100 以内所有奇数和为: " + result);
}

循环嵌套

和其他编程语言一样,Java 允许循环嵌套。如果把一个循环放在另一个循环体内,那么就可以形成嵌套循环。

嵌套循环既可以是 for循环嵌套 while 循环,也可以是 while 循环嵌套 do-while 循环 …… 即各种类型的循环都可以作为外层循环,也可以作为内层循环。

假设外层循环的循环次数为 n 次,内层循环的循环次数为 m 次,那么内层循环的循环体实际上需要执行 n×m 次。

for、do-while 和 while 的区别:

名称 概念 适用场景
for 根据循环次数限制做多少次重复操作 适合循环次数是已知的操作
while 当满足什么条件的时候,才做某种操作 适合循环次数是未知的操作
do-while 先执行一次,在判断是否满足条件 适合至少执行一次的循环操作

foreach 语句

foreach 循环语句是 Java 1.5 的新特征之一,在 遍历数组、集合 方面,foreach 为开发者提供了极大的方便。

foreach 循环语句的语法格式如下:

1
2
3
for(类型 变量名:集合) {
语句块;
}

其中,“类型”为集合或数组中 元素的类型,“变量名”表示集合或数组中的每一个元素“集合”是被遍历的集合对象或数组。

样例,假设有一个数组,采用 for 语句遍历数组的方式如下:

1
2
3
4
5
6
7
// 声明并初始化数组
int[] numbers = { 43, 32, 53, 54, 75, 7, 10 };
System.out.println("----for----");
// for语句
for (int i = 0; i < numbers.length; i++) {
System.out.println("Count is:" + numbers[i]);
}

关于数组集合会在教程后面详细介绍,这里我们只需要大概了解就可以。numbers.length 是获得数组的长度,length 是数组的属性,numbers[i] 是通过数组下标访问数组元素。

那么采用 for-each 循环语句遍历数组的方式如下:

1
2
3
4
5
6
7
// 声明并初始化int数组
int[] numbers = { 43, 32, 53, 54, 75, 7, 10 };
System.out.println("----for each----");
// for-each语句
for (int item : numbers) {
System.out.println("Count is:" + item);
}

从示例中可以发现,item 不是循环变量,它保存了集合中的元素,for-each 语句将集合中的元素一一取出来,并保存到 item 中,这个过程中不需要使用循环变量,通过数组下标访问数组中的元素。可见 for-each 语句在遍历集合的时候要简单方便得多。

–> 注意:foreach 循环迭代数组(集合)元素时,并不能改变数组(集合)元素的值

当使用 foreach 循环来迭代输出数组元素或集合元素时,通常不要对循环变量进行赋值,虽然这种赋值在语法上是允许的,但没有太大的实际意义,而且极容易引起错误。例如下面程序。

1
2
3
4
5
6
7
8
9
10
11
public static void main(String[] args) {
String[] languages={"Java","ASP.NET","Python","C#","PHP"};
System.out.println("时下流行的编程语言:");
// 使用 foreach 循环语句遍历数组
for(String lang:languages) {
lang = "Google";
System.out.println(lang);
}

System.out.println(languages[0]);
}

运行上边程序,将看到如下结果:

1
2
3
4
5
6
7
时下流行的编程语言:
Google
Google
Google
Google
Google
Java

可以发现,由于在 foreach 循环中对数组元素进行赋值,结果导致不能正确遍历数组元素,不能正确地取出每个数组元素的值。而且当再次访问第一个数组元素时,发现数组元素的值依然没有改变。

===================================================

原理解析:

当使用 foreach 来迭代访问数组元素时,foreach 中的循环变量相当于一个临时变量,系统会把数组元素依次赋给这个临时变量,而这个临时变量并不是数组元素,它只是保存了数组元素的值。因此,如果希望改变数组元素的值,则不能使用这种 foreach 循环。


break 语句

某些时候需要在某种条件出现时强行终止循环,而不是等到循环条件为 false 时才退出循环。此时,可以使用 break 来完成这个功能。

Java 中,break 语句有 3 种作用:

  • break,可用于直接结束当前循环
  • 在 switch 语句中终止一个语句序列
  • 实现 goto 的功能

直接结束当前循环

使用 break 语句直接强行退出循环的示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
public class HelloWorld {
public static void main(String[] args) {

// 打印单数
for (int j = 1; j < 10; j++) {
if(0==j%2)
break; // 如果是双数,直接结束循环

System.out.println(j);
}
}
}

输出如下:

1
1

break 语句能用于任何 Java 循环中,包括人们有意设置的无限循环。

在一系列嵌套循环中使用 break 语句时,它将仅仅终止最里面的循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static void main(String[] args) {
// 外循环,循环5次
for (int i = 0; i < 5; i++) {
System.out.print("第" + (i + 1) + "次循环:");
// 内循环,设计为循环10次
for (int j = 0; j < 10; j++) {
// 判断j是否等于3,如果是,则终止循环
if (j == 3) {
break;
}
System.out.print("内循环的第" + (j + 1) + "次循环\t");
}
System.out.println();
}
}

break 带标签实现 goto 功能

Java 提供了一种带标签的 break 语句,用于跳出多重嵌套的循环语句,可以实现 goto 的功能。

通过使用扩展的 break 语句,可以终止执行一个或者几个任意代码块,这些代码块不必是一个循环或一个 switch 语句的一部分。同时这种扩展的 break 语句带有标签,可以明确指定从何处重新开始执行。

标签 break 语句的通用格式如下:

break label;

label 是标识代码块的标签。被加标签的代码块必须包围 break 语句,但是它不需要直接包围 break 的块。也就是说,可以使用一个加标签的 break 语句来退出一系列的嵌套块,但是不能使用 break 语句将控制权传递到不包含 break 语句的代码块。

用标签(label)可以指定一个代码块,标签可以是任何合法有效的 Java 标识符,后跟一个冒号。

下面是使用带标签的break 语句的示例。

1
2
3
4
5
6
7
8
9
10
11
12
public class GotoDemo {
public static void main(String[] args) {
label: for (int i = 0; i < 10; i++) {
for (int j = 0; j < 8; j++) {
System.out.println(j);
if (j % 2 != 0) {
break label;
}
}
}
}
}

程序执行结果:

1
2
0
1

可以发现,加上标签的代码块可以作为 break 语句的对象,使程序在加标签的块的结尾继续执行。

标签语句必须和循环匹配使用,使用时书写在对应的循环语句的上面,标签语句以冒号结束。如果需要中断标签语句对应的循环,可以采用 break 后面跟标签名的方式。

但注意,标签语句可以独立使用, Java 不会报错


switch 语句中终止一个语句序列

break 在 switch 语句中可终止一个语句序列,就是在每个 case 子句块的最后添加语句 “break;”,具体使用可见分支结构中的 switch 语句。


continue 语句

与 break 语句一样, 它将中断正常的控制流程。与 break 语句的区别在于:continue 并不是中断循环语句,而是中止当前迭代的循环,进入下一次的迭代。

简单来讲,continue 是忽略循环语句的当次迭代。

1
2
3
4
5
6
7
8
9
10
11
12
public class HelloWorld {
public static void main(String[] args) {

//打印单数
for (int j = 0; j < 10; j++) {
if(0==j%2)
continue; //如果是双数,后面的代码不执行,直接进行下一次循环

System.out.println(j);
}
}
}

程序输出:

1
2
3
4
5
1
3
5
7
9

–> continue label

同 break 语句一样,continue 语句同样可以配合 label 使用。

带标签的 continue 语句示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
public class GotoDemo {
public static void main(String[] args) {
label: for (int i = 0; i < 10; i++) {
for (int j = 0; j < 8; j++) {
System.out.println(j);
if (j % 2 != 0) {
continue label;
}
}
}
}
}

注意,与 break label 使用时的区别。

输出如下:

1
2
3
4
5
6
7
8
9
10
11
0
1
0
1
0
1
0
1
0
1
...

Author

Waldeinsamkeit

Posted on

2017-10-16

Updated on

2021-04-26

Licensed under

You need to set install_url to use ShareThis. Please set it in _config.yml.

Comments

You forgot to set the shortname for Disqus. Please set it in _config.yml.