流程控制
Böhm-Jacopini 定理:任何算法都可以由顺序、分支和循环三种基本结构组合而成。
顺序结构
顺序结构是最简单也最常见的流程:代码自上而下依次运行。
示例:
System.out.println(1);
System.out.println(2);
System.out.println(3);
选择结构
if 族
if 语句会依次判断表达式,只有匹配成功后,隶属于该 if 语句后的代码块才会立即执行,而且后续分支的代码块会被跳过。
📝 注意:
if语句只支持布尔表达式。if语句后的代码块如果只有一行代码,那么花括号是可以省略的。
单分支 if
条件满足才执行。
if (表达式) {
// 表达式结果为 true 时执行
}
示例:
if (age > 18) {
System.out.println("成年人");
}
双分支 if-else
二选一。
if (表达式) {
// 表达式结果为 true 时执行
} else {
// 表达式结果为 false 时执行
}
示例:
if (n % 2 == 0) {
System.out.println("偶数");
} else {
System.out.println("基数");
}
多分支 if-else if-else
多条件互斥。
if (表达式1) {
// 表达式 1 结果为 true 时执行
} else if (条件2) {
// 表达式 2 结果为 true 时执行
} else {
// 所有条件都为 false 时执行
}
示例:
if (score >= 90) {
System.out.println("优秀");
} else if (score >= 80) {
System.out.println("良好");
} else {
System.out.println("合格");
}
switch 语句
switch 语句比较适合固定值的多路选择。
📝 注意:
- 如果省略
break会产生“穿透”,导致继续执行后续case代码。default在所有case不匹配时执行,可放在任意位置。- 要确保
case标签的值是编译时常量,不能包含方法调用、new等动态操作。switch表达式的类型必须与case标签的值类型一致(或可自动转换)。- 不能使用
null作为switch表达式的值,否则抛出NullPointerException。
switch (表达式) {
case 值1:
// 表达式结果为值 1 时执行
break;
case 值2:
// 表达式结果为值 2 时执行
break;
default:
// 默认代码块,表达式的值不为上述的所有值时执行
}
switch 表达式支持的类型包括:
- 整数类型:支持
byte、short、int和char类型,但是不支持long类型。 - 包装类:从 Java 5 开始支持的包装类类型,包括
Byte、Short、Integer、Character。 - 枚举类型:Java 5 引入了枚举类型,
switch可以使用枚举常量。 - 字符串类型:从 Java 7 开始,
switch语句支持字符串类型,可以使用字符串的字面量作为表达式。
示例:
switch (day) {
case "Monday":
System.out.println("周一");
break;
case "Tuesday":
System.out.println("周二");
break;
case "Wednesday":
System.out.println("周三");
break;
case "Thursday":
System.out.println("周四");
break;
case "Friday":
System.out.println("周五");
break;
default:
System.out.println("周末");
}
switch 表达式不支持 long 类型的原因
switch 表达式不支持 long 类型与在多线程环境下的非原子性读写风险有关,因为在 32 位架构中,long 类型(64 位)需要分两次操作(高 32 位和低 32 位)进行读写。如果线程同步机制不足,switch 在读取 long 值时可能会观察到高 32 位和低 32 位来自不同写入操作,从而可能会组合出一个“中间值”。这个“中间值”可能既不符合任何有效的 case 分支,也可能意外的匹配到完全无关的 case 分支,从而引发 不可预测的程序行为(如跳转到随机地址)。相比之下,int 等小于等于 32 位的类型在读写时都是原子的,即使同步机制不完善,读取的值仍能保证是单次写入操作的结果,而非“中间值”。
循环结构
for 循环
经典形式
for (初始化; 条件; 迭代) {
// 循环体
}
示例:
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
增强 for-each
for-each 语法更精简,适合遍历集合或数组。
for (数据类型 变量名 : 数组或集合) {
// 循环体
}
示例:
for (int num : array) {
System.out.println(num);
}
while 循环
先判断再执行。
while (条件) {
// 循环体
}
示例:
BufferedReader reader = new BufferedReader(new FileReader("data.txt"));
String line;
while ((line = reader.readLine()) != null) { // 动态判断条件
System.out.println(line);
}
do-while 循环
至少执行一次。
do {
// 循环体
} while (条件);
示例:
Scanner scanner = new Scanner(System.in);
String pwd = "123456";
String input;
do {
System.out.print("请输入正确的密码: ");
input = scanner.nextLine();
} while (!pwd.equals(input));
System.out.println("密码正确!");
跳转语句
break 语句
用于退出循环或 switch 语句。
示例:
for (int i = 1; i <= 10; i++) {
if (i == 5) {
break;
}
System.out.println(i);
}
continue 语句
跳过当前循环的剩余部分,进入下一次循环。
示例:
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) {
continue;
}
System.out.println(i);
}
label 语句
用于跳转到指定标签位置。
📝 注意:
label必须紧邻循环语句之前,并且不能跨方法或代码块引用。
示例 1:
// 定义外层循环标签
outerLoop:
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (i == 1 && j == 1) {
System.out.println("找到目标,跳出所有循环");
// 跳出到标签处
break outerLoop;
}
System.out.println("i=" + i + ", j=" + j);
}
}
示例 2:
// 定义外层循环标签
outerLoop:
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (i == 1) {
// 跳出到标签处
continue outerLoop;
}
System.out.println("i=" + i + ", j=" + j);
}
}
嵌套控制结构
流程控制结构可以相互嵌套使用,比如在循环中嵌套条件语句、在条件语句中嵌套循环、多层循环等。
最佳实践
- 避免过深的嵌套。
- 为复杂的条件添加注释。
- 避免在循环中重复计算。
- 在
switch语句中不要忘记break。

Comments NOTHING