条件与循环
这一课你将能做到
- 用 if/else、switch(含 JDK 17 箭头语法)表达业务分支,如订单状态流转、权限判断
- 用 for/while/增强 for 处理批量数据,正确使用 break/continue 控制流程
- 独立写出九九乘法表、数组求最值等经典练习,具备刷算法题的语法基础
为什么要学
顺序执行的代码只能「一条道走到黑」,真实业务全是分支和重复:请求合法性校验走 if,订单状态判断走 switch,批量写库走循环。本站后端的 Service 层,随便一个方法都是「校验参数(if)→ 状态判断(switch)→ 批量处理(for)」的组合。
语法上这一课不难,难点在把业务语言翻译成控制流:「金额大于 0 且用户未封禁才允许下单」→ if (amount > 0 && !user.isBanned())。练的就是这个翻译能力。
先建立图像
控制流三种基本结构:
顺序 分支 循环
──▶──▶── 条件? ┌─条件成立?─┐
├─true──▶ A │ ▼ │
└─false─▶ B └──否──▶ 出来
(条件成立就绕回去再干一遍)
跟着做
步骤 1:if / else if / else
新建 ScoreDemo.java:
public class ScoreDemo {
public static void main(String[] args) {
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 amount = 500;
boolean vip = true;
if (amount >= 300 && vip) {
System.out.println("可用 vip 折扣"); // 短路:amount 不够就不会看 vip
}
}
}
步骤 2:switch 传统写法与箭头语法
public class OrderStatusDemo {
public static void main(String[] args) {
int status = 2; // 假设 1=待支付 2=已支付 3=已发货 4=已完成
// 老写法:容易漏 break 导致「击穿」
switch (status) {
case 1:
System.out.println("待支付");
break; // 不写 break,会继续执行下一个 case!
case 2:
System.out.println("已支付");
break;
default:
System.out.println("未知状态");
}
// JDK 14+ 箭头语法:无击穿,可以直接返回值(本站后端主流写法)
String desc = switch (status) {
case 1 -> "待支付";
case 2 -> "已支付";
case 3, 4 -> "已" + (status == 3 ? "发货" : "完成"); // 多标签合并
default -> "未知状态";
};
System.out.println(desc);
// switch 还能作用于 String 和枚举
String role = "admin";
switch (role) {
case "admin" -> System.out.println("管理员权限");
case "user" -> System.out.println("普通用户");
default -> System.out.println("非法角色");
}
}
}
步骤 3:for 循环三件套
public class LoopDemo {
public static void main(String[] args) {
// 经典 for:初始化; 条件; 步进
for (int i = 1; i <= 5; i++) {
System.out.print(i + " "); // 1 2 3 4 5
}
System.out.println();
// 累加求和:1 加到 100
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
}
System.out.println("1+2+...+100 = " + sum); // 5050
// 嵌套循环:九九乘法表
for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= i; j++) {
System.out.printf("%d×%d=%-4d", j, i, i * j);
}
System.out.println();
}
}
}
步骤 4:while / do-while / 增强 for
import java.util.List;
public class WhileDemo {
public static void main(String[] args) {
// while:先判断再执行,可能一次都不跑
int retries = 0;
while (retries < 3) {
System.out.println("第 " + (retries + 1) + " 次重试调用下游接口");
retries++;
}
// do-while:先执行再判断,至少跑一次(适合「先提示再校验输入」场景)
int count = 10;
do {
System.out.println("do-while 至少执行一次,count=" + count);
} while (count < 5); // 条件为 false 退出,但上面已执行过一次
// 增强 for(for-each):遍历数组/集合,最常用
int[] nums = {3, 7, 1, 9};
int max = nums[0];
for (int n : nums) { // 逐个取出元素
if (n > max) max = n;
}
System.out.println("最大值 = " + max);
// 集合同样适用(第 9 课展开)
for (String s : List.of("mysql", "redis")) {
System.out.println("依赖中间件: " + s);
}
}
}
步骤 5:break 与 continue
public class BreakDemo {
public static void main(String[] args) {
int[] ids = {101, 102, -1, 104}; // -1 表示脏数据
for (int id : ids) {
if (id == -1) {
System.out.println("遇到脏数据,终止处理");
break; // 跳出整个循环
}
if (id % 2 == 0) {
continue; // 跳过本次,直接进入下一轮
}
System.out.println("处理奇数 id: " + id); // 只打印 101
}
// 带标签的 break:一次跳出多层嵌套(少用,知道即可)
outer:
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (i * j == 2) break outer; // 直接跳出外层
System.out.printf("(%d,%d) ", i, j);
}
}
System.out.println();
}
}
讲清楚要点
- 条件必须是 boolean:Java 不接受
if (1)、if (x = 5) 这种 C 风格写法,if (x = 5) 直接编译报错——误用 = 代替 == 会被编译器拦住。
- switch 击穿是老写法最大坑:漏
break 会顺势执行后面所有 case。箭头语法从根上消灭了这个问题,新代码一律用箭头。
- for 三段各有职责:初始化只跑一次、条件每次循环前判断、步进每次循环体后执行。循环变量
i 的作用域仅限循环内。
- while 求先判断,do-while 求至少一次:绝大多数场景用 while/for,do-while 只在「必须先做一次」时用。
- 增强 for 不能改结构:遍历集合时不能增删元素(会 ConcurrentModificationException),要删就用迭代器或
removeIf。
- 死循环有正当用途:
while (true) + 内部 break 是「不断轮询直到成功」的标准写法,比如重试逻辑,但必须有退出条件。
你可能会懵的地方
-
i++ 和 ++i 有区别吗?
单独成语句时无区别。作为表达式时有:int a = 5; int b = a++ 得 b=5(先取值再加);int c = 5; int d = ++c 得 d=6(先加再取值)。工程里建议只单独使用,避免炫技。
-
switch 能作用在 long/float 上吗?
不能。传统 switch 只支持 byte/short/char/int、其包装类、枚举和 String(long/float/double/boolean 都不行)。
-
增强 for 想要下标怎么办?
用普通 for:for (int i = 0; i < arr.length; i++)。需要边遍历边知道位置时只能这么写。
-
循环里 return 和 break 什么区别?
return 直接结束整个方法;break 只结束当前循环。方法里循环后面还有代码时,两者行为不同。
-
为什么条件判断要「先判 null 再调方法」?
if (user != null && user.getAge() > 18) 中 && 短路保证 user 为 null 时不会执行右边的 user.getAge(),避免 NPE。顺序写反了照样炸。
错法对照
| 错法 | 问题 | 正解 |
|---|
if (x = 5) | 编译错误:需要 boolean | if (x == 5) |
| switch case 漏 break | 击穿执行后续 case | 用箭头语法 case 1 -> |
for (int i = 0; i <= arr.length; i++) | 最后一次越界抛异常 | 条件用 < |
循环内 int i 写成循环外声明 | 多个循环共用变量易出错 | 每个循环独立声明,作用域最小化 |
while (true) 没有退出条件 | 程序卡死 | 内部必须有 break/return/异常出口 |
if (a == 1); System.out.println("x"); | 分号成空语句,println 恒执行 | if 后不要随手加分号 |
卡点急救
- 循环打印不出来/只打一行:检查条件是否一开始就为 false(如
i <= 0);确认没有在 if 后多写分号。
- 死循环卡住终端:Windows 按
Ctrl + C 终止进程。然后检查步进语句是否写了(漏 i++ 是头号原因)。
- ArrayIndexOutOfBoundsException:索引越界。最后访问的合法下标是
length - 1,条件从 <= 改 <。
- switch 变量报「不兼容的类型」:检查作用对象,long/double/boolean 不支持,先转成 int 或改用 if。
- 嵌套循环缩进对不上:每一层花括号独立缩进 4 空格,IDE 里
Ctrl+Alt+L(IDEA)一键格式化。
面试常问
-
while 和 do-while 的区别?
while 先判断后执行,可能零次;do-while 先执行后判断,至少一次。
-
switch 支持哪些类型?
byte/short/char/int 及其包装类、枚举、String(JDK 7+)。本质是按 int 比较,包装类自动拆箱——包装类为 null 时会 NPE。
-
break、continue、return 的区别?
break 跳出当前循环/switch;continue 跳过本次进入下一轮;return 结束方法。嵌套时作用范围不同,带标签 break 可跳出外层但可读性差。
-
&& 与 & 在条件判断中的区别?
&& 短路与,左 false 则右不执行;& 位运算/非短路,两边都算。判空保护必须用 &&。
-
switch 的箭头语法和传统语法区别?(JDK 新特性题)
箭头语法无击穿、case 可作表达式返回值、可多标签合并、必须穷尽所有分支(配合枚举时编译器检查遗漏)。
自测三问
- 传统 switch 漏写 break 会发生什么?箭头语法如何避免这个问题?
- 用一个循环求 100 以内所有 7 的倍数之和,写出代码。
for (int i = 0; i <= arr.length; i++) 为什么错?正确写法是什么?
小结一句话
if/switch 负责分岔、for/while 负责重复,break/continue 精确控制循环节奏;新代码用箭头 switch 消灭击穿,判空永远把 null 检查写在 && 左边。
延伸