流程控制
这是什么:流程控制 = 让程序做选择、重复干活的语法,主角是 if/switch 分支和 for/while 循环。
为什么用:到目前为止,程序都是「从上往下一条条执行」。可现实里总得判断「今天要不要带伞」,也得把 40 个成绩挨个加起来——没有分支和循环,你连批量处理数据都做不到。
如何用:本章先写 if/else 和 switch 做选择,再上 for、while 管重复,最后练嵌套循环和 break、continue。
if / else 和 switch:做选择
public class FlowDemo {
public static void main(String[] args) {
int score = 75;
if (score >= 90) {
System.out.println("优秀");
} else if (score >= 60) {
System.out.println("及格,继续加油");
} else {
System.out.println("挂科预警!");
}
int day = 6;
switch (day) {
case 6:
case 7: // case 穿透:6 和 7 共用一段
System.out.println("周末快乐!");
break;
default:
System.out.println("工作日,搬砖");
break;
}
}
}
输出:
及格,继续加油
周末快乐!
if 从上往下逐个检查条件,命中一个就进对应分支,后面的分支连看都不看;所有条件都不中,走 else 兜底。这决定了条件顺序很重要:上面代码如果把 score >= 60 放在 score >= 90 前面,75 分会被"及格"分支截胡,永远轮不到"优秀"——范围窄的条件放前面。
if 括号里放的是一个 boolean 表达式(值只能是 true 或 false),能用的比较和逻辑运算符一览:
| 运算符 | 含义 | 例子 | ||
|---|---|---|---|---|
== / != |
等于 / 不等于 | count == 0 |
||
> / < / >= / <= |
大小比较 | score >= 60 |
||
&& |
并且(两边都真才真) | age >= 18 && hasId |
||
| ` | ` | 或者(一边真就真) | day == 6 || day == 7 |
|
! |
取反 | !isVip |
组合示例:
int age = 20;
boolean hasTicket = true;
if (age >= 18 && hasTicket) {
System.out.println("检票通过,请入场");
} else {
System.out.println("无法入场");
}
输出:
检票通过,请入场
switch 适合"固定几个选项多选一"。它的执行方式要特别注意:命中一个 case 后,程序会从那里一路往下执行,直到撞见 break 才停——这叫 case 穿透。利用穿透可以让多个选项共用一段代码(6 和 7 都是周末),但漏写 break 是新手经典坑,本页下方翻车现场有它的事故报告。JDK 14+ 还有箭头写法 case 6 ->,能不用写 break,见到能认出即可。
if 还是 switch?给出选择依据:
| 场景 | 选谁 | 原因 | ||
|---|---|---|---|---|
| 条件是范围(大于、小于、区间) | if | switch 只能匹配具体值,做不了范围 | ||
| 条件是组合逻辑(并且/或者) | if | && ` |
` 更直观 | |
| 一个变量匹配固定几个值 | switch | case 一列,选项一目了然 |
for、while、do-while:重复干活
public class LoopDemo {
public static void main(String[] args) {
// for:知道要循环几次时用
for (int i = 1; i <= 3; i++) {
System.out.println("第 " + i + " 次俯卧撑");
}
// while:满足条件就一直做
int water = 3;
while (water > 0) {
System.out.println("喝一口水,剩 " + water);
water--;
}
// do-while:先干一次,再问"还继续吗"
int count = 0;
do {
count++;
} while (count < 0); // 条件一开始就不满足,但也执行了 1 次
System.out.println("do-while 执行了 " + count + " 次");
}
}
输出:
第 1 次俯卧撑
第 2 次俯卧撑
第 3 次俯卧撑
喝一口水,剩 3
喝一口水,剩 2
喝一口水,剩 1
do-while 执行了 1 次
把 for 的结构拆开看,括号里是三段式,用分号隔开:
| 部分 | 例子 | 执行时机 |
|---|---|---|
| 初始化 | int i = 1 |
进循环前执行一次 |
| 条件 | i <= 3 |
每轮开始前检查,不满足就退出 |
| 更新 | i++ |
每轮结尾执行,推动循环靠近终点 |
i++ 是"自增 1"的简写,等价于 i = i + 1;对应还有 i-- 自减。for 循环的变量 i 只活在循环里——出了那对大括号它就消失了(这叫作用域,方法章还会细讲)。
三种循环的本质区别只有一个:条件检查的时机。for 和 while 是"先检查再干活",一次都可能不干;do-while 是"先干活再检查",保底干一次。日常写代码,for 和 while 覆盖绝大多数场景。
| 语法 | 什么时候用 |
|---|---|
for |
循环次数明确(如"跑 10 遍") |
while |
只知道条件,不知道几轮(如"水没喝完就继续") |
do-while |
至少干一次,再判断继不继续 |
switch |
固定几个选项多选一 |
嵌套循环:循环里套循环
循环体内还可以再放循环,外层转一圈,内层转一整圈——经典的九九乘法表:
public class NineTable {
public static void main(String[] args) {
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= i; j++) {
System.out.print(j + "×" + i + "=" + (i * j) + "\t");
}
System.out.println(); // 内层打完一行,换行
}
}
}
输出:
1×1=1
1×2=2 2×2=4
1×3=3 2×3=6 3×3=9
读这段代码的诀窍:外层 i 管"第几行",内层 j 管"这一行打几项"。i 是 1 时 j 转一轮,i 是 2 时 j 转两轮……注意这里用了 print(不换行)和 println(换行)的组合拳,\t 是制表符,负责对齐。把 i <= 3 改成 i <= 9,完整的九九乘法表就出来了。
嵌套循环的总执行次数是内外圈数的乘积:外层 9 次 × 内层最多 9 次 ≈ 81 次内层循环。嵌套超过三层通常意味着代码该拆了,这是后话。
break 和 continue:循环的遥控器
- break:整个循环立刻结束,"不干了,走人"
- continue:跳过本轮剩余代码,直接进入下一轮,"这句跳过,继续"
public class BreakDemo {
public static void main(String[] args) {
for (int i = 1; i <= 5; i++) {
if (i == 3) {
continue; // 跳过 3
}
if (i == 5) {
break; // 到 5 直接收工
}
System.out.println("处理第 " + i + " 件");
}
System.out.println("循环结束");
}
}
输出:
处理第 1 件
处理第 2 件
处理第 4 件
循环结束
i 等于 3 时 continue 让"打印"被跳过;i 等于 5 时 break 让整个循环戛然而止。这两招在"遍历中寻找、遍历中过滤"的场景天天用:找到目标就 break,不合规的就 continue。
大括号惯例
Java 社区的铁规矩:哪怕里面只有一行,也写上大括号 {}。省大括号一时爽,回头加代码直接埋 bug。
// 危险写法:看起来加了一行,实际只有第一行受 if 管
if (isVIP)
System.out.println("欢迎贵宾");
System.out.println("赠送优惠券"); // ❌ 无论是不是 VIP 都会执行!
大括号圈定了"哪些行受 if 管辖"。没有大括号时,if 只管紧跟的那一句。上面第二行缩进得再乖巧,语法上它已经跳出 if 的管辖,无条件执行——缩进骗得了人眼,骗不了编译器。
❓ 常见问题
Q1:&& 和 & 有什么区别?
日常写 && 就对了。&& 有"短路"能力:左边已经能定生死时,右边根本不执行。比如 age != 0 && 10 / age > 1,当 age 是 0 时左边为假,右边的除法不会执行,避免了除零错误。单个 & 没有这个保护,两边都会算。
Q2:while 循环停不下来怎么办?
八成是死循环——条件永远为真,或忘了在循环体内更新条件变量(比如忘了 water--)。命令行里按 Ctrl + C 强制终止程序。写 while 时先自问一句:"什么变量在变化?它如何推动条件走向不成立?"
Q3:if 判断两个字符串相等能用 == 吗?
不能,这是 Java 名坑:== 比的是"是不是同一个对象"而不是内容,比字符串内容必须用 equals。原理在字符串章血泪警告一节讲透,这里先埋个种子。
Q4:循环变量为什么习惯叫 i、j?
index(索引)的传统缩写,从数学求和符号沿用至今,全世界的程序员都认。真正的业务代码里,能起有意义的名字就起(如 score、index),纯计数的循环用 i/j/k 完全没问题。
⚠️ 新手翻车现场
翻车一:switch 漏写 break
int day = 6;
switch (day) {
case 6:
System.out.println("周六");
case 7:
System.out.println("周日");
break;
}
完整输出:
周六
周日
问题:本想只打印"周六",但 case 6 没有 break,穿透到了 case 7 的代码,多打了一行。穿透不报错,属于"程序活着但结果不对"的暗伤,最难查。
修正:每个 case 的代码结尾都补 break;,除非你刻意利用穿透共享代码。
翻车二:if 条件里写赋值
int score = 60;
if (score = 100) { // ❌ 编译报错
System.out.println("满分!");
}
完整报错:
错误: 不兼容的类型: int无法转换为boolean
问题:= 是赋值,== 才是比较。在 C/JS 里这是悄悄生效的坑,好在 Java 的 if 括号里必须是 boolean,int 塞进去直接编译报错——强类型又一次救了你。
修正:比较相等一律写两个等号 score == 100。
翻车三:for 括号后多打了一个分号
for (int i = 0; i < 3; i++);
{
System.out.println("跑了 " + i + " 圈"); // ❌ 报错:找不到 i
}
问题:for (...) 后面那个分号让循环体变成了"空语句"——循环空转三轮,下面的大括号块和 for 已经无关,还因为出了 i 的作用域而报错。一个分号,双重暴击。
修正:删掉 for 括号后的分号。这个坑的变体(if 后多分号)同理。
翻车四:while 忘了更新条件
int water = 3;
while (water > 0) {
System.out.println("喝水"); // ❌ 没人让 water 减小,死循环
}
问题:条件 water > 0 永远成立,程序陷入死循环,风扇起飞。
修正:循环体里补 water--;。记住口诀:while 循环体内,必须有变量朝"条件不成立"的方向变化。
🎯 什么时候用什么结构
| 需求 | 首选结构 |
|---|---|
| 成绩分档、多条件组合判断 | if / else if / else |
| 菜单选项、星期几等固定值分发 | switch |
| 已知次数的重复(打 10 行、遍历数组) | for |
| 满足条件才继续(用户没输对就重问) | while |
| 至少执行一次(先展示菜单再问要不要继续) | do-while |
| 遍历中提前退出 / 跳过某些项 | 循环 + break / continue |
📝 本章小结
- if / else if / else 自上而下检查,命中即停;范围窄的条件放前面
- switch 命中后一路穿透直到 break;固定值多选一用它,范围判断用 if
- for 三段式(初始化;条件;更新),次数明确用它;while 只看条件;do-while 保底一次
- break 结束整个循环,continue 跳过本轮
- 无论多短,分支和循环体都写大括号;if 括号里必须是 boolean,比较用
== - 记忆口诀:次数明确用 for,条件不明用 while,先斩后奏 do-while,多选一找 switch,break 记得带。
记忆锚点:程序是一本"选择冒险"游戏书——if 是岔路口(选一条路走),switch 是菜单点菜(只上一个菜),for 是"绕操场跑 10 圈"(圈数已知),while 是"跑到没水喝为止"(条件说了算),break 是中途退赛,continue 是这一圈偷个懒。
动手改
- 把
score改成 59、60、90 分别跑一遍,验证分支走向 - 用 for 循环打印 1~100 里所有的偶数(提示:
i % 2 == 0) - 写一个 while 循环,从 5 倒数打印到 1
- 把九九乘法表的外层改成
i <= 9,跑出完整表格 - 写一个 for 循环打印 1~20,遇到 7 的倍数用 continue 跳过、遇到 15 用 break 收工,先纸上推演再运行验证
下一章:数组,一次管理一批数据 🐸