条件判断与循环
学习目标
- 能根据问题选择
if、传统switch或switch表达式表达条件分支。 - 会使用
for、增强for、while和do-while,并能检查循环是否一定终止。 - 理解
break、continue、标签和早返回的作用范围,减少不必要的嵌套。
核心知识点
专业术语
- 控制流(control flow):决定语句执行顺序的分支、循环和跳转。
- 条件分支(conditional branch):根据布尔表达式选择一条或多条执行路径。
- switch 语句/表达式(switch statement/expression):按离散标签分类;表达式会产生一个值。
- 迭代(iteration):重复执行一段代码;
for、while和do-while都是迭代结构。 - 循环不变量(loop invariant):每轮开始前都成立的事实,有助于检查循环逻辑。
- 守卫式返回(guard clause):先处理无效或特殊输入并立即返回,使主路径保持平坦。
白话解释与边界
if、else 与早返回
if 适合范围判断、组合条件和早返回。先处理无效或特殊输入并立即 return,可以把主路径保持在较浅的嵌套层级。
switch 语句与表达式
switch 适合有限的离散选项,例如菜单、状态或枚举。传统 switch 的冒号分支可能继续执行下一个 case,需要 break、return 或有意利用穿透;箭头分支不会意外穿透。switch 表达式必须为每条路径产生值,通常用 default 覆盖未知输入。
for 与增强 for
for 适合次数或索引明确的循环,增强 for 适合遍历数组和集合。循环的初始化、条件和更新必须共同推动状态变化,否则就会无限循环。
while 与 do-while
while 先判断条件,可能一次也不执行;do-while 先执行再判断,至少执行一次。
break 与 continue
break 结束最近一层循环或 switch,continue 跳过本轮剩余代码并进入下一轮。标签可以跳出多层循环,但低频且容易降低可读性,通常提取方法或使用标志变量更清楚。早返回把非法输入挡在入口,避免多层 if;它不是“少写校验”,而是更早明确失败。
| 结构 | 适合场景 | 主要边界 |
|---|---|---|
if/else | 范围判断、组合条件、守卫条件 | 嵌套太深时应提取命名条件或方法 |
switch 语句 | 固定标签执行多条语句 | 冒号写法要注意穿透和 break |
switch 表达式 | 把分类直接转换为一个值 | 所有路径必须产值 |
for/增强 for | 次数、索引或遍历集合 | 修改集合结构可能触发并发修改异常 |
while/do-while | 条件驱动或至少执行一次 | 必须保证条件最终变化为假 |
常用用法
if 与早返回:先处理非法输入
早返回把边界条件挡在入口,减少嵌套;条件复杂时应提取有名字的方法。
// 输入:level 接收 score=80;只有 score 小于 0 或大于 100 时才会早返回 "invalid"。
public class GuardDemo {
static String level(int score) {
// 作用:早返回把边界条件挡在入口,减少嵌套;条件复杂时应提取有名字的方法。
if (score < 0 || score > 100) {
return "invalid";
}
return score >= 60 ? "pass" : "retry";
}
public static void main(String[] args) {
System.out.println(level(80));
// 输出:pass
}
}for:按次数或索引遍历
循环初始化、条件和更新要共同推动状态变化,否则会出现死循环或越界。
public class ForDemo {
public static void main(String[] args) {
int total = 0;
// 初始状态:total 当前为 0。
for (int i = 1; i <= 3; i++) {
// 作用:循环初始化、条件和更新要共同推动状态变化,否则会出现死循环或越界。
total += i;
}
System.out.println(total);
// 输出:6
}
}不常用但需要知道
do-while:至少执行一次
当业务要求先执行一次再判断时使用 do-while,否则优先使用更直观的 while。
// 初始状态:attempts 为 0;循环体先将它增加到 1,然后才检查 attempts < 1。
public class DoWhileDemo {
public static void main(String[] args) {
int attempts = 0;
// 初始状态:attempts 当前为 0。
do {
attempts++;
} while (attempts < 1);
// 关键变化:while (attempts < 1) 在 attempts++ 把 attempts 从 0 变为 1 后判断为 false,do-while 因而恰好执行一次。
System.out.println(attempts);
// 输出:1
}
}标签循环:一次跳出多层循环
标签适合极少数明确的多层跳出场景;多数时候提取方法或使用结果变量更易维护。
public class LabelLoopDemo {
public static void main(String[] args) {
int found = 0;
// 关键变化:found 接收表达式 0 的计算结果。
// 初始状态:found 的初始值为 0。
search:
for (int row = 0; row < 2; row++) {
for (int column = 0; column < 2; column++) {
found = row * 2 + column;
break search;
}
}
System.out.println(found);
// 输出:0
}
}简单案例
public class FlowDemo {
static String classifyScore(int score) {
if (score < 0 || score > 100) {
return "invalid"; // 早返回:先挡住非法输入
}
return switch (score / 10) {
case 10, 9 -> "A";
case 8 -> "B";
case 7 -> "C";
default -> "D";
};
}
public static void main(String[] args) {
int score = 86;
System.out.println(classifyScore(score));
// 输出:B
int total = 0;
for (int value : new int[] {1, -2, 3, 0, 100}) {
if (value < 0) {
continue; // 跳过负数,继续下一轮
}
if (value == 0) {
break; // 遇到 0,结束最近一层循环
}
total += value;
}
System.out.println(total);
// 输出:4
int attempts = 0;
while (attempts < 2) {
attempts++;
}
int shown = 0;
do {
shown++;
} while (shown < 1);
System.out.println("loops=" + attempts + "," + shown);
// 输出:loops=2,1
}
}classifyScore 先用早返回过滤非法分数,再用 switch 表达式得到等级。增强 for 依次读取数组元素,continue 忽略负数,break 在遇到 0 时结束;while 可能零次执行,而 do-while 保证至少执行一次。
易混点
- 传统
switch是执行语句,switch表达式必须产生值;箭头分支和冒号分支的穿透规则不同。 break只结束最近一层循环或switch,continue只影响循环的当前轮次。while可能一次不执行,do-while一定至少执行一次;不要只看条件文字判断次数。for的更新表达式不一定是i++,但必须存在某种让循环走向终止的状态变化。- 早返回需要先校验输入再进入主路径;它不能代替对业务边界的明确说明。
课后小问
while (condition)和do { ... } while (condition)的关键差异是什么? 答案:while先判断条件,可能零次执行;do-while先执行循环体,因此至少执行一次。 解析:读取菜单、重试一次输入等场景常要求先显示或先执行动作,此时do-while更直接;如果输入可能已经无效,先判断的while更安全。为什么下面的
switch可能同时打印两个结果? 答案:冒号分支没有break时会发生穿透,匹配一个case后继续执行后面的分支。 解析:可以在每个分支末尾加break或return,也可以改用箭头分支;如果确实需要共享逻辑,应在注释中明确说明有意穿透。continue和break都能跳过代码,它们的作用分别是什么? 答案:continue跳过当前轮剩余代码并开始下一轮,break直接结束最近一层循环。 解析:统计数据时可以用continue忽略不符合条件的项,但遇到结束标记时应使用break;选错会导致漏算、死循环或多处理数据。
本节小结
if适合范围和组合条件,switch适合离散标签,表达式版本还会直接产生分类结果。for、增强for、while和do-while的差别主要在迭代来源与首次判断时机。break结束循环,continue跳过当前轮,标签跳转低频且应谨慎使用。- 早返回把非法状态挡在入口,循环则必须有清楚的终止条件和状态变化。
快速回顾
- 能根据条件是范围还是离散标签选择
if或switch。 - 能判断一个循环是否可能零次执行、是否至少执行一次以及是否会终止。
- 能说明
break、continue和早返回分别影响哪一层控制流。 - 能读懂
switch箭头分支和传统冒号分支的差异。
继续阅读
- 数据类型和变量见:数据类型与变量
- 方法、参数、重载和递归见:方法、参数、重载与递归
阿源的知识库