就像有感知的生物一样,程序必须在执行过程中控制它的世界,并做出选择。在Java中,你要使用执行控制语句来作出选择。
一、流程控制基础概念
1.1 流程控制的重要性
流程控制结构决定了程序执行的顺序和逻辑分支,是编程语言中最基础也是最重要的组成部分。Java继承了C/C++的大多数流程控制结构,但去除了一些容易出错的部分(如goto语句),并增加了一些安全性检查。
1.2 Java中的流程控制分类
Java中的流程控制主要分为三类:
条件语句:if-else, switch-case
循环语句:while, do-while, for, 增强for循环
流程中断语句:break, continue, return
二、条件语句
2.1 if-else语句
if-else是最基础的条件分支结构,语法如下:
if (布尔表达式) {// 表达式为true时执行
} else {// 表达式为false时执行
}
2.1.1 多条件分支
可以嵌套使用if-else实现多条件分支:
if (condition1) {// condition1为true时执行
} else if (condition2) {// condition2为true时执行
} else {// 其他情况执行
}
2.1.2 注意事项
布尔表达式必须返回boolean类型(与C/C++不同,不能使用数值)
即使只有一条语句,也建议使用花括号(提高可读性和避免错误)
else与最近的if匹配
2.2 switch语句
switch用于多值选择,语法如下:
switch (表达式) {case 值1:// 代码块1break;case 值2:// 代码块2break;default:// 默认代码块
}
2.2.1 switch特性
表达式类型可以是:
基本类型:byte, short, char, int
包装类:Byte, Short, Character, Integer
枚举类型
String(Java 7+)
case值必须是编译时常量
需要break语句防止"贯穿"(fall-through)现象
default分支是可选的
2.2.2 Java 12+的switch表达式
Java 12引入了更简洁的switch表达式语法:
int numLetters = switch (day) {case MON, FRI, SUN -> 6;case TUE -> 7;case THU, SAT -> 8;case WED -> 9;default -> throw new IllegalStateException();
};
三、循环语句
3.1 while循环
while循环在条件为真时重复执行代码块:
while (布尔表达式) {// 循环体
}
3.1.1 注意事项
循环体可能一次都不执行(先检查条件)
需要确保循环条件最终会变为false,否则会导致无限循环
循环体内通常应修改影响循环条件的变量
3.2 do-while循环
do-while循环先执行一次循环体,再检查条件:
do {// 循环体
} while (布尔表达式);
3.2.1 与while的区别
循环体至少执行一次
分号不能省略
3.3 for循环
for循环提供了更紧凑的循环语法:
for (初始化; 布尔表达式; 步进) {// 循环体
}
3.3.1 for循环执行流程
执行初始化表达式(仅一次)
检查布尔表达式:
如果为true,执行循环体
如果为false,退出循环
执行步进表达式
重复步骤2-3
3.3.2 特殊形式
可以省略初始化、布尔表达式或步进(但分号不能省略)
可以在初始化部分声明多个变量(类型相同)
可以在初始化部分使用已有变量
for (int i = 0, j = 10; i < j; i++, j--) {System.out.println(i + " " + j);
}
3.4 增强for循环(for-each)
Java 5引入的增强for循环简化了数组和集合的遍历:
for (元素类型 变量名 : 数组或集合) {// 使用变量名访问元素
}
3.4.1 特点
更简洁的语法
避免使用显式索引
不能修改原数组/集合元素(对于基本类型数组)
不能获取当前索引
3.4.2 实现原理
增强for循环对数组和Iterable接口的实现类处理方式不同:
数组:编译为基于索引的标准for循环
Iterable:使用iterator()方法获取迭代器
四、流程中断语句
4.1 break
break用于:
退出switch语句的case块
提前终止循环
4.1.1 带标签的break
Java支持标签(label)语法,可以跳出多层嵌套循环:
outer:
for (int i = 0; i < 10; i++) {for (int j = 0; j < 10; j++) {if (i * j > 50) {break outer; // 跳出外层循环}}
}
4.2 continue
continue跳过当前循环的剩余部分,直接开始下一次循环:
for (int i = 0; i < 10; i++) {if (i % 2 == 0) {continue; // 跳过偶数}System.out.println(i);
}
4.2.1 带标签的continue
类似break,continue也可以使用标签:
outer:
for (int i = 0; i < 10; i++) {for (int j = 0; j < 10; j++) {if (j > i) {continue outer; // 跳到外层循环的下一次迭代}System.out.println(i + " " + j);}
}
4.3 return
return用于从方法中返回:
无返回值方法:直接返回
有返回值方法:返回指定值
public int max(int a, int b) {if (a > b) {return a;}return b;
}
五、特殊流程控制
5.1 嵌套循环
循环可以多层嵌套,但应注意:
嵌套层次不宜过深(通常不超过3层)
内层循环应尽可能简单
考虑使用带标签的break/continue简化控制
5.2 递归
方法可以调用自身,形成递归:
public int factorial(int n) {if (n <= 1) {return 1;}return n * factorial(n - 1);
}
5.2.1 递归注意事项
必须有终止条件
每次递归应使问题规模减小
Java默认的调用栈深度有限(可通过-Xss参数调整)
递归可能比迭代效率低
六、Java与C/C++流程控制的区别
布尔表达式:Java必须使用boolean类型,不能使用数值
goto语句:Java没有goto,但标签+break/continue可以实现类似功能
for循环变量作用域:Java可以在for初始化部分声明变量,作用域限于循环
增强for循环:Java特有的简化语法
switch语句:
Java 7+支持String
case值必须是编译时常量
必须有break防止贯穿(除非有意为之)
七、最佳实践与常见陷阱
7.1 最佳实践
代码块始终使用花括号:即使只有一条语句
switch语句始终包含default分支:处理未预期的值
避免深层嵌套:使用方法提取或提前返回简化逻辑
循环条件应明显可见:避免隐藏的无限循环
优先使用增强for循环:当不需要索引时
7.2 常见陷阱
if语句缺少花括号:
if (condition)statement1;statement2; // 无论condition如何都会执行
switch贯穿问题:
switch (x) {case 1: System.out.println("1");case 2: System.out.println("2"); // 当x=1时也会执行 }
浮点数比较:
for (double d = 0.1; d != 1.0; d += 0.1) {// 可能因浮点精度问题导致无限循环 }
修改增强for循环的集合:
for (String s : list) {list.remove(s); // 抛出ConcurrentModificationException }
八、现代Java中的流程控制改进
8.1 Java 14的switch表达式(正式版)
Java 14使switch表达式成为正式特性:
int numLetters = switch (day) {case MON, FRI, SUN -> 6;case TUE -> 7;case THU, SAT -> 8;case WED -> {System.out.println("Wednesday");yield 9; // 使用yield返回值}default -> 0;
};
8.2 模式匹配(预览特性)
Java 14+引入了模式匹配的预览特性:
// instanceof模式匹配(Java 16正式)
if (obj instanceof String s) {System.out.println(s.length()); // 直接使用s
}// switch模式匹配(预览)
switch (obj) {case Integer i -> System.out.println("Integer: " + i);case String s -> System.out.println("String: " + s);default -> System.out.println("Other");
}
九、foreach设计哲学
9.1 设计目标
简化迭代语法:隐藏迭代器细节
统一访问方式:数组和集合使用相同语法
减少错误:避免越界和修改异常
9.2 foreach修改集合问题
List<String> list = new ArrayList<>();
// 错误方式(抛出ConcurrentModificationException)
for (String s : list) {if (s.equals("remove")) list.remove(s);
}// 正确方式1:使用迭代器
Iterator<String> it = list.iterator();
while (it.hasNext()) {if (it.next().equals("remove")) it.remove();
}// 正确方式2:Java 8+ removeIf
list.removeIf(s -> s.equals("remove"));
9.3 多维数组遍历优化
// 低效方式(多次数组访问)
for (int i = 0; i < matrix.length; i++) {for (int j = 0; j < matrix[i].length; j++) {sum += matrix[i][j];}
}// 高效方式(缓存行数组)
for (int[] row : matrix) {for (int val : row) {sum += val;}
}
结语:通过深入理解这些流程控制机制,我们可以编写出更高效、更健壮的Java代码,同时为适应Java语言的持续演进做好准备。