前言
如果把程序比作一条路,那么流程控制语句就是路上的红绿灯、岔路口和指示牌。
默认情况下,Java 代码会按照从上到下的顺序依次执行。但真实业务显然不会永远"一条路走到底":
- 用户登录成功和失败,需要执行不同的逻辑;
- 批量处理订单,需要重复执行同一段代码;
- 查找到目标数据后,希望提前结束循环;
- 遇到无效数据时,希望跳过本轮处理;
- 某些条件不满足时,希望直接结束整个方法。
这些需求分别对应 Java 中的条件判断、循环结构和跳转语句。
本文将系统梳理以下内容:
if、if-else和多分支判断- 传统
switch与增强switch for、增强for、while、do-whilebreak、continue、return- 标签语句与多层循环跳转
- 常见错误及实际开发建议
- 一个综合案例
一、先理解什么是流程控制
Java 中常见的程序执行结构可以分为三类。
1. 顺序结构
顺序结构是最简单的结构,代码从上到下依次执行。
public class Demo {
public static void main(String[] args) {
System.out.println("第一步:打开冰箱");
System.out.println("第二步:放入饮料");
System.out.println("第三步:关闭冰箱");
}
}
执行结果:
第一步:打开冰箱
第二步:放入饮料
第三步:关闭冰箱
这里没有判断,也没有循环,执行顺序和代码书写顺序完全一致。
2. 分支结构
分支结构会根据条件选择不同的执行路线,常用语句包括:
ifif-elseif-else if-elseswitch
3. 循环结构
循环结构用于重复执行某段代码,常用语句包括:
for- 增强
for whiledo-while
除此之外,Java 还提供了 break、continue 和 return 等语句,用来改变程序原来的执行方向。
二、条件判断:if 语句
2.1 单分支 if
当某段代码只需要在条件成立时执行,可以使用单分支 if。
语法如下:
if (条件表达式) {
条件成立时执行的代码;
}
例如,判断用户是否成年:
int age = 20;
if (age >= 18) {
System.out.println("用户已经成年");
}
当 age >= 18 的结果为 true 时,才会执行大括号中的代码。
需要特别注意:Java 的条件表达式必须是 boolean 类型,不能像某些语言一样使用整数代替真假。
下面的写法无法通过编译:
int number = 1;
// 错误:int 不能自动转换为 boolean
if (number) {
System.out.println("条件成立");
}
正确写法应该明确给出判断条件:
if (number != 0) {
System.out.println("number 不等于 0");
}
2.2 双分支 if-else
当程序需要在两种结果中选择一种时,可以使用 if-else。
int score = 58;
if (score >= 60) {
System.out.println("考试及格");
} else {
System.out.println("考试不及格");
}
它的逻辑很直接:
- 条件为
true,执行if中的代码; - 条件为
false,执行else中的代码。
两个分支只会执行其中一个。
2.3 多分支 if-else if-else
如果业务中存在多个区间,可以使用多分支结构。
int score = 86;
if (score >= 90) {
System.out.println("等级:优秀");
} else if (score >= 80) {
System.out.println("等级:良好");
} else if (score >= 60) {
System.out.println("等级:及格");
} else {
System.out.println("等级:不及格");
}
程序会从上到下依次判断,一旦某个条件成立,后面的分支就不会再执行。
因此,多分支条件的顺序很重要。
下面这种写法就有问题:
int score = 95;
if (score >= 60) {
System.out.println("及格");
} else if (score >= 90) {
System.out.println("优秀");
}
虽然分数是 95,但第一个条件 score >= 60 已经成立,所以程序只会输出"及格","优秀"分支永远没有机会执行。
对于成绩、价格、年龄这类区间判断,通常应该从范围更严格的条件开始判断:
if (score >= 90) {
System.out.println("优秀");
} else if (score >= 60) {
System.out.println("及格");
} else {
System.out.println("不及格");
}
2.4 嵌套 if
if 内部还可以继续使用 if。
int age = 22;
boolean hasTicket = true;
if (age >= 18) {
if (hasTicket) {
System.out.println("允许入场");
} else {
System.out.println("请先购票");
}
} else {
System.out.println("未成年人不能入场");
}
嵌套判断本身没有问题,但层数太多时,代码会越来越难读。
实际开发中,可以使用逻辑运算符简化:
if (age >= 18 && hasTicket) {
System.out.println("允许入场");
}
也可以通过提前 return 减少嵌套。
2.5 逻辑运算与短路判断
条件判断经常会配合下面几个逻辑运算符:
| 运算符 | 含义 | 示例 |
|---|---|---|
&& |
并且,两个条件都成立 | age >= 18 && hasTicket |
| || | 或,成立一个即可 | age>=18 && !hasTicket |
! |
取反 | !isLogin |
&& 和 || 具有短路特性。
例如:
String username = null;
if (username != null && !username.isBlank()) {
System.out.println("用户名有效");
}
程序先判断 username != null。
因为这个条件为 false,整个 && 表达式已经不可能成立,所以右边的 username.isBlank() 不会执行,也就避免了空指针异常。
如果把顺序反过来:
if (!username.isBlank() && username != null) {
System.out.println("用户名有效");
}
程序会先调用 username.isBlank(),此时就会抛出 NullPointerException。
因此,"先判空,再调用对象的方法"是一个很实用的习惯。
2.6 三元运算符:简单判断的简写
对于非常简单的二选一赋值,可以使用三元运算符:
条件 ? 条件成立时的结果 : 条件不成立时的结果
例如:
int age = 20;
String result = age >= 18 ? "成年人" : "未成年人";
System.out.println(result);
三元运算符适合简单场景。如果判断逻辑很长,继续使用 if-else 通常更清楚。
不建议写出层层嵌套的三元表达式:
String level = score >= 90 ? "优秀"
: score >= 80 ? "良好"
: score >= 60 ? "及格"
: "不及格";
它虽然能运行,但阅读成本并不低。代码不是越短越好,能让别人快速看懂更加重要。
三、多值判断:switch 语句
当一个变量需要与多个确定值进行匹配时,switch 往往比一长串 if-else 更直观。
3.1 传统 switch 写法
int day = 3;
switch (day) {
case 1:
System.out.println("星期一");
break;
case 2:
System.out.println("星期二");
break;
case 3:
System.out.println("星期三");
break;
case 4:
System.out.println("星期四");
break;
case 5:
System.out.println("星期五");
break;
case 6:
case 7:
System.out.println("周末");
break;
default:
System.out.println("输入的日期不合法");
}
传统 switch 中几个关键字的作用如下:
case:定义一个可以匹配的值;break:结束当前switch;default:所有case都不匹配时执行。
default 不是语法上绝对必需的,但保留它可以处理意料之外的数据。
3.2 case 穿透现象
传统 switch 中,如果某个 case 后面没有写 break,程序会继续执行后面的分支,这种现象叫作 case 穿透。
int number = 1;
switch (number) {
case 1:
System.out.println("A");
case 2:
System.out.println("B");
case 3:
System.out.println("C");
default:
System.out.println("结束");
}
输出结果:
A
B
C
结束
很多初学者会觉得:number 明明等于 1,为什么后面的内容也执行了?
原因是程序从 case 1 进入后,一直没有遇到 break,于是继续向下执行。
当然,穿透并不总是错误。有时可以利用它合并分支:
int month = 2;
switch (month) {
case 1:
case 2:
case 3:
System.out.println("第一季度");
break;
case 4:
case 5:
case 6:
System.out.println("第二季度");
break;
default:
System.out.println("其他月份");
}
不过,只要不是故意使用穿透,最好及时写上 break。
3.3 增强 switch
从 JDK 14 开始,switch 表达式已经成为正式特性,可以使用箭头语法:
int day = 6;
switch (day) {
case 1 -> System.out.println("星期一");
case 2 -> System.out.println("星期二");
case 3 -> System.out.println("星期三");
case 4 -> System.out.println("星期四");
case 5 -> System.out.println("星期五");
case 6, 7 -> System.out.println("周末");
default -> System.out.println("日期不合法");
}
箭头写法不会发生传统 case 穿透,因此不需要在每个分支后面写 break。
增强 switch 还可以直接产生一个值:
int day = 6;
String dayType = switch (day) {
case 1, 2, 3, 4, 5 -> "工作日";
case 6, 7 -> "休息日";
default -> "无效日期";
};
System.out.println(dayType);
如果一个分支中需要执行多行代码,可以使用代码块和 yield:
int level = 2;
String description = switch (level) {
case 1 -> "普通会员";
case 2 -> {
System.out.println("正在加载高级会员权益");
yield "高级会员";
}
case 3 -> "超级会员";
default -> "未知等级";
};
System.out.println(description);
这里的 yield 表示为整个 switch 表达式提供一个结果,它和结束方法的 return 不是一回事。
3.4 if 和 switch 应该怎么选
我通常按照下面的思路来选择:
更适合使用 if 的情况
-
判断的是范围,例如分数、年龄、价格;
-
条件中包含
&&、||等复杂逻辑; -
每个分支判断的变量不完全相同;
-
只有一两个简单分支。
if (age >= 18 && hasTicket) {
System.out.println("允许入场");
}
更适合使用 switch 的情况
-
围绕同一个变量进行判断;
-
判断的是几个确定值;
-
状态、类型、菜单选项比较多;
-
希望直接根据选项产生一个结果。
String text = switch (status) {
case 0 -> "待支付";
case 1 -> "已支付";
case 2 -> "已发货";
case 3 -> "已完成";
default -> "未知状态";
};
四、循环结构
循环解决的是"重复执行"问题。
一个完整的循环通常包含四部分:
- 初始化循环变量;
- 判断循环条件;
- 执行循环体;
- 更新循环变量。
如果更新变量或终止条件写错,程序很容易陷入死循环。
4.1 for 循环
for 循环适合循环次数比较明确的场景。
基本语法:
for (初始化语句; 循环条件; 更新语句) {
循环体;
}
例如,输出 1 到 5:
for (int i = 1; i <= 5; i++) {
System.out.println("当前数字:" + i);
}
执行过程可以理解为:
初始化 i = 1
↓
判断 i <= 5
↓
执行循环体
↓
执行 i++
↓
重新判断 i <= 5
初始化语句只执行一次,条件判断和变量更新会重复执行。
4.2 使用 for 完成累加
计算 1 到 100 的和:
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
}
System.out.println("1 到 100 的和为:" + sum);
计算 1 到 100 之间所有偶数的和:
int sum = 0;
for (int i = 2; i <= 100; i += 2) {
sum += i;
}
System.out.println("偶数之和:" + sum);
也可以从 1 开始循环,然后在循环内部判断:
int sum = 0;
for (int i = 1; i <= 100; i++) {
if (i % 2 == 0) {
sum += i;
}
}
前一种写法循环次数更少,后一种写法更容易看出"筛选偶数"的过程。实际开发时,应优先保证逻辑清楚,再考虑这类微小优化。
4.3 for 循环中的变量作用域
如果循环变量定义在 for 内部,那么它只能在循环内部使用。
for (int i = 0; i < 3; i++) {
System.out.println(i);
}
// 这里无法访问 i
// System.out.println(i);
如果循环结束后仍然需要使用变量,可以把它声明在循环外部:
int i;
for (i = 0; i < 3; i++) {
System.out.println(i);
}
System.out.println("循环结束后的 i:" + i);
4.4 增强 for 循环
增强 for 也经常被称为 foreach,适合遍历数组或集合。
int[] scores = {90, 76, 88, 59};
for (int score : scores) {
System.out.println(score);
}
它表示:每次从 scores 中取出一个元素,放入变量 score。
增强 for 写起来简洁,但它也有明显限制:
- 不方便获取当前下标;
- 不适合需要倒序遍历的场景;
- 不方便指定步长;
- 给循环变量重新赋值,通常不会修改原数组元素。
例如:
int[] numbers = {1, 2, 3};
for (int number : numbers) {
number = number * 10;
}
for (int number : numbers) {
System.out.println(number);
}
输出仍然是:
1
2
3
因为 number 只是当前数组元素值的一份副本。
如果确实需要修改数组元素,可以使用普通 for:
for (int i = 0; i < numbers.length; i++) {
numbers[i] = numbers[i] * 10;
}
4.5 while 循环
while 适合"暂时不知道需要循环多少次,只知道什么时候结束"的场景。
语法如下:
while (条件表达式) {
循环体;
}
例如:
int count = 1;
while (count <= 5) {
System.out.println("第 " + count + " 次执行");
count++;
}
while 会先判断条件,再决定是否执行循环体。如果条件一开始就是 false,循环体一次也不会执行。
int number = 10;
while (number < 5) {
System.out.println(number);
}
上面的代码不会产生任何输出。
4.6 while 的典型使用场景
例如,模拟任务重试:
int retryCount = 0;
boolean success = false;
while (!success && retryCount < 3) {
retryCount++;
System.out.println("正在进行第 " + retryCount + " 次尝试");
if (retryCount == 2) {
success = true;
}
}
if (success) {
System.out.println("任务执行成功");
} else {
System.out.println("任务执行失败");
}
在这个例子中,我们不知道任务会在第几次成功,只知道:
- 成功后停止;
- 最多尝试三次。
这就是比较典型的 while 场景。
4.7 do-while 循环
do-while 与 while 的最大区别是:do-while 会先执行一次循环体,再判断条件。
语法如下:
do {
循环体;
} while (条件表达式);
注意最后的分号不能漏掉。
例如:
int number = 10;
do {
System.out.println("number = " + number);
number++;
} while (number < 5);
虽然 number < 5 一开始就是 false,但程序仍然会输出一次:
number = 10
因此,do-while 适合至少需要执行一次的场景,例如:
- 第一次显示系统菜单;
- 第一次读取用户输入;
- 第一次执行连接操作;
- 执行操作后询问用户是否继续。
4.8 三种循环怎么选
| 循环类型 | 特点 | 常见场景 |
|---|---|---|
for |
循环次数通常比较明确 | 计数、按下标遍历数组 |
增强 for |
写法简洁,不关心下标 | 只读取数组或集合元素 |
while |
先判断,可能一次不执行 | 重试、等待、条件未知的循环 |
do-while |
先执行,至少执行一次 | 菜单、输入校验、交互程序 |
这并不是强制规定。很多场景用不同循环都能实现,选择最容易表达业务含义的写法即可。
五、循环嵌套
循环内部可以继续编写循环,这叫作嵌套循环。
例如,打印乘法表:
for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= i; j++) {
System.out.print(j + "×" + i + "=" + (i * j) + "\t");
}
System.out.println();
}
外层循环控制行数,内层循环控制每一行输出多少个表达式。
再看一个遍历二维数组的例子:
int[][] matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
for (int row = 0; row < matrix.length; row++) {
for (int col = 0; col < matrix[row].length; col++) {
System.out.print(matrix[row][col] + " ");
}
System.out.println();
}
这段代码的运行结果是:
1 2 3
4 5 6
7 8 9
外层循环控制行数,内层循环控制列数,每一行输出结束后调用 System.out.println() 换行。
嵌套循环非常常见,但层数不宜过深。三四层循环叠在一起时,通常已经很难阅读,也可能带来明显的性能问题。
六、跳转语句
6.1 break:立即结束循环
break 用于立即结束当前循环。
for (int i = 1; i <= 10; i++) {
if (i == 5) {
break;
}
System.out.println(i);
}
输出结果:
1
2
3
4
当 i == 5 时执行 break,整个循环立即结束。
需要注意:break 结束的是离它最近的一层循环。
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
if (j == 2) {
break;
}
System.out.println("i = " + i + ", j = " + j);
}
}
这里的 break 只会结束内层循环,外层循环仍然会继续。
6.2 continue:跳过本次循环
continue 不会结束整个循环,它只会跳过当前这一轮剩余的代码,然后进入下一轮。
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) {
continue;
}
System.out.println(i);
}
输出结果:
1
3
5
7
9
遇到偶数时执行 continue,本轮后面的输出语句会被跳过。
可以简单记成:
break:后面的轮次也不执行了;continue:只是不执行本轮剩余代码。
6.3 while 中使用 continue 要小心
下面这段代码会进入死循环:
int i = 0;
while (i < 5) {
if (i == 2) {
continue;
}
System.out.println(i);
i++;
}
当 i 等于 2 时,程序直接执行 continue,导致后面的 i++ 被跳过。
于是 i 永远等于 2,循环条件永远成立。
可以改成:
int i = 0;
while (i < 5) {
i++;
if (i == 2) {
continue;
}
System.out.println(i);
}
或者在执行 continue 之前手动更新变量:
int i = 0;
while (i < 5) {
if (i == 2) {
i++;
continue;
}
System.out.println(i);
i++;
}
相比之下,普通 for 执行 continue 后,还会执行更新表达式,所以这种问题在 for 中相对少见。
6.4 return:结束整个方法
return 的作用范围比 break 更大,它结束的是当前整个方法。
public static void checkAge(int age) {
if (age < 0) {
System.out.println("年龄不能小于 0");
return;
}
if (age < 18) {
System.out.println("未成年人");
return;
}
System.out.println("成年人");
}
当执行到 return 时,方法后面的代码不再执行。
return 经常用于提前处理异常情况,这种写法也叫"提前返回"或"守卫式写法"。
例如,下面的嵌套比较深:
public static void submitOrder(boolean login, boolean hasAddress) {
if (login) {
if (hasAddress) {
System.out.println("订单提交成功");
} else {
System.out.println("请先填写地址");
}
} else {
System.out.println("请先登录");
}
}
使用提前返回后会更加平整:
public static void submitOrder(boolean login, boolean hasAddress) {
if (!login) {
System.out.println("请先登录");
return;
}
if (!hasAddress) {
System.out.println("请先填写地址");
return;
}
System.out.println("订单提交成功");
}
这种写法在实际项目中很常见。
6.5 break、continue、return 的区别
| 语句 | 作用 | 影响范围 |
|---|---|---|
break |
结束循环或传统 switch |
当前循环或 switch |
continue |
跳过当前这一轮 | 当前循环的一次迭代 |
return |
结束当前方法 | 整个方法 |
看一个对比:
public static void test() {
for (int i = 1; i <= 5; i++) {
if (i == 2) {
continue;
}
if (i == 4) {
break;
}
System.out.println(i);
}
System.out.println("循环已经结束");
}
输出:
1
3
循环已经结束
如果把 break 改成 return:
if (i == 4) {
return;
}
那么"循环已经结束"也不会输出,因为整个 test() 方法已经结束。
七、标签语句:跳出多层循环
Java 没有可以任意跳转的 goto 语句,但支持带标签的 break 和 continue。
例如,在二维数组中查找目标值:
int[][] matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
int target = 5;
outer:
for (int row = 0; row < matrix.length; row++) {
for (int col = 0; col < matrix[row].length; col++) {
if (matrix[row][col] == target) {
System.out.println(
"找到目标,位置:" + row + ", " + col
);
break outer;
}
}
}
System.out.println("查找结束");
如果只写普通 break,只能结束内层循环;写成 break outer,可以直接结束被 outer 标记的外层循环。
同样,也可以使用带标签的 continue:
outer:
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
if (j == 2) {
continue outer;
}
System.out.println("i = " + i + ", j = " + j);
}
}
不过,标签语句容易让执行流程变得跳跃。除非确实是在处理多层循环,否则不建议频繁使用。
很多时候,把查找逻辑提取成一个方法,再通过 return 返回结果会更清晰:
public static boolean contains(int[][] matrix, int target) {
for (int[] row : matrix) {
for (int number : row) {
if (number == target) {
return true;
}
}
}
return false;
}
八、一个综合案例:学生成绩统计
下面通过一个完整案例,把条件判断、循环、continue、break 和 return 串联起来。
需求如下:
-
遍历学生成绩;
-
跳过不合法的成绩;
-
统计有效人数、总分、平均分和最高分;
-
统计及格人数;
-
如果遇到满分,记录第一位满分学生;
-
如果没有有效成绩,直接结束方法。
public class ScoreStatistics {
public static void main(String[] args) { String[] names = {"小明", "小红", "小刚", "小李", "小周"}; int[] scores = {86, 102, 59, 100, 76}; printStatistics(names, scores); } public static void printStatistics(String[] names, int[] scores) { if (names == null || scores == null) { System.out.println("学生信息不能为空"); return; } if (names.length != scores.length) { System.out.println("姓名数量和成绩数量不一致"); return; } int validCount = 0; int passCount = 0; int totalScore = 0; int highestScore = -1; for (int i = 0; i < scores.length; i++) { int score = scores[i]; if (score < 0 || score > 100) { System.out.println( "跳过无效成绩:" + names[i] + "," + score ); continue; } validCount++; totalScore += score; if (score >= 60) { passCount++; } if (score > highestScore) { highestScore = score; } } if (validCount == 0) { System.out.println("没有可以统计的有效成绩"); return; } String firstFullScoreStudent = null; for (int i = 0; i < scores.length; i++) { if (scores[i] == 100) { firstFullScoreStudent = names[i]; break; } } double average = totalScore * 1.0 / validCount; String level = switch ((int) average / 10) { case 10, 9 -> "整体表现优秀"; case 8 -> "整体表现良好"; case 7 -> "整体表现中等"; case 6 -> "整体达到及格水平"; default -> "整体成绩需要提升"; }; System.out.println(); System.out.println("有效人数:" + validCount); System.out.println("及格人数:" + passCount); System.out.println("最高分:" + highestScore); System.out.println("平均分:" + average); System.out.println("班级评价:" + level); if (firstFullScoreStudent != null) { System.out.println("第一位满分学生:" + firstFullScoreStudent); } else { System.out.println("本次没有满分学生"); } }}
这个案例中:
if用于参数校验和成绩判断;for用于遍历数组;continue用于跳过无效成绩;break用于找到第一位满分学生后提前结束查找;return用于参数错误或没有有效成绩时结束方法;- 增强
switch用于生成班级评价。
流程控制语句往往不是各自孤立使用的,真正写业务代码时,它们通常会组合在一起。
九、流程控制中最常见的坑
9.1 if 后面误写分号
int age = 10;
if (age >= 18); {
System.out.println("成年人");
}
这里的分号代表一条空语句,后面的大括号已经不属于 if,所以无论条件是否成立都会执行。
正确写法:
if (age >= 18) {
System.out.println("成年人");
}
9.2 省略大括号带来的问题
Java 允许单条语句省略大括号:
if (age >= 18)
System.out.println("成年人");
但如果后面又增加一行代码:
if (age >= 18)
System.out.println("成年人");
System.out.println("允许注册");
第二个输出语句并不属于 if。
为了避免维护时出现误解,建议即使只有一条语句,也保留大括号:
if (age >= 18) {
System.out.println("成年人");
System.out.println("允许注册");
}
9.3 使用 == 比较字符串
下面的代码可能得不到预期结果:
String role = new String("admin");
if (role == "admin") {
System.out.println("管理员");
}
== 比较的是两个引用是否指向同一个对象,而不是字符串内容是否相同。
应该使用 equals():
if ("admin".equals(role)) {
System.out.println("管理员");
}
把确定不为 null 的字符串写在前面,还可以避免空指针异常。
9.4 数组边界写错
数组下标从 0 开始,最后一个下标是 length - 1。
错误写法:
int[] numbers = {10, 20, 30};
for (int i = 0; i <= numbers.length; i++) {
System.out.println(numbers[i]);
}
当 i == numbers.length 时,会抛出数组下标越界异常。
正确写法:
for (int i = 0; i < numbers.length; i++) {
System.out.println(numbers[i]);
}
涉及数组下标时,通常使用 < length,而不是 <= length。
9.5 忘记更新循环变量
int i = 1;
while (i <= 5) {
System.out.println(i);
}
这里没有修改 i,所以 i <= 5 永远成立,最终形成死循环。
正确写法:
int i = 1;
while (i <= 5) {
System.out.println(i);
i++;
}
编写循环时,可以快速检查三个问题:
- 循环条件什么时候会变成
false? - 循环体是否真的在改变相关变量?
continue会不会跳过变量更新?
9.6 误以为 switch 中的 break 能结束外层循环
while (true) {
int command = 0;
switch (command) {
case 0:
System.out.println("退出");
break;
default:
System.out.println("继续运行");
}
}
这里的 break 只会结束 switch,不会结束外面的 while,因此循环仍然会继续。
可以使用布尔变量:
boolean running = true;
while (running) {
int command = 0;
switch (command) {
case 0:
System.out.println("退出");
running = false;
break;
default:
System.out.println("继续运行");
}
}
也可以在单独的方法中使用 return,或者在确有必要时使用带标签的 break。
9.7 条件嵌套过深
下面这种代码虽然可以运行,但读起来很累:
if (user != null) {
if (user.isLogin()) {
if (user.hasPermission()) {
if (order != null) {
System.out.println("开始处理订单");
}
}
}
}
可以改成提前返回:
if (user == null) {
return;
}
if (!user.isLogin()) {
return;
}
if (!user.hasPermission()) {
return;
}
if (order == null) {
return;
}
System.out.println("开始处理订单");
流程控制写得好不好,关键不在于用了多少语法,而在于执行路径是否清楚。
十、写好流程控制代码的几个建议
1. 条件名称尽量表达业务含义
与其把复杂条件全部堆在 if 中:
if (age >= 18 && balance >= 100 && !disabled) {
// ...
}
不如先提取一个有含义的变量:
boolean canPurchase =
age >= 18
&& balance >= 100
&& !disabled;
if (canPurchase) {
System.out.println("允许购买");
}
如果判断逻辑还要复用,可以进一步提取成方法。
2. 优先处理异常情况
先处理空值、非法参数和无权限等情况,然后再编写真正的业务逻辑,可以减少嵌套层数。
3. 不要为了少写几行代码牺牲可读性
复杂三元表达式、连续多层嵌套、过度使用标签,都可能让代码看起来很"高级",但维护起来并不轻松。
4. 明确跳转语句的作用范围
写下 break、continue 或 return 时,最好清楚回答:
- 它结束的是本轮循环,还是整个循环?
- 它结束的是内层循环,还是外层循环?
- 它会不会直接结束整个方法?
- 它会不会跳过变量更新?
5. 循环首先保证正确,再考虑性能
遍历几百个元素时,清晰通常比微小的性能差异更重要。但如果是多层循环处理大量数据,就需要关注时间复杂度。
例如两个长度都是 n 的嵌套循环,执行次数可能接近 n²。数据量变大后,性能差距会十分明显。