Java 完全指南 / 06 - 控制流:if/else、switch、for、while、增强 for
06 - 控制流:if/else、switch、for、while、增强 for
if / else 条件判断
public class IfDemo {
public static void main(String[] args) {
int score = 85;
// 基本 if-else
if (score >= 60) {
System.out.println("及格");
} else {
System.out.println("不及格");
}
// 多分支 if-else if-else
if (score >= 90) {
System.out.println("优秀");
} else if (score >= 80) {
System.out.println("良好");
} else if (score >= 60) {
System.out.println("及格");
} else {
System.out.println("不及格");
}
// 嵌套 if(不推荐过深)
boolean isStudent = true;
if (score >= 60) {
if (isStudent) {
System.out.println("学生及格");
}
}
}
}
if 表达式(JDK 17+,JEP 394 Pattern Matching)
// 模式匹配
Object obj = "Hello Java";
if (obj instanceof String s && s.length() > 5) {
System.out.println("长字符串: " + s.toUpperCase());
}
// 在 return 中使用模式匹配
public static String describe(Object obj) {
if (obj instanceof Integer i) {
return "整数: " + i;
} else if (obj instanceof String s) {
return "字符串: " + s;
} else {
return "未知类型";
}
}
switch 语句与表达式
传统 switch 语句
public class SwitchDemo {
public static void main(String[] args) {
String day = "WEDNESDAY";
// 传统写法
switch (day) {
case "MONDAY":
case "TUESDAY":
case "WEDNESDAY":
case "THURSDAY":
case "FRIDAY":
System.out.println("工作日");
break;
case "SATURDAY":
case "SUNDAY":
System.out.println("周末");
break;
default:
System.out.println("未知");
}
}
}
⚠️ 传统 switch 忘记
break会导致 case 穿透(fall-through),这是常见的 bug 来源。
switch 表达式(JDK 14+,JEP 361)
public class SwitchExpressionDemo {
public static void main(String[] args) {
String day = "WEDNESDAY";
// 箭头语法(不会穿透)
String type = switch (day) {
case "MONDAY", "TUESDAY", "WEDNESDAY",
"THURSDAY", "FRIDAY" -> "工作日";
case "SATURDAY", "SUNDAY" -> "周末";
default -> "未知";
};
System.out.println(day + " 是 " + type);
// yield 返回值(代码块写法)
int numLetters = switch (day) {
case "MONDAY", "FRIDAY", "SUNDAY" -> 6;
case "TUESDAY" -> 7;
case "WEDNESDAY" -> {
System.out.println("Wednesday!");
yield 9; // 代码块中用 yield 返回
}
default -> {
String s = day;
yield s.length();
}
};
System.out.println("字母数: " + numLetters);
}
}
switch 模式匹配(JDK 21+)
public class SwitchPatternDemo {
// 模式匹配 + switch
static String formatValue(Object obj) {
return switch (obj) {
case Integer i when i < 0 -> "负整数: " + i;
case Integer i -> "正整数: " + i;
case String s when s.isEmpty() -> "空字符串";
case String s -> "字符串: " + s;
case null -> "null 值";
default -> "其他: " + obj.getClass().getSimpleName();
};
}
sealed interface Shape permits Circle, Rectangle {}
record Circle(double radius) implements Shape {}
record Rectangle(double w, double h) implements Shape {}
static double area(Shape shape) {
return switch (shape) {
case Circle c -> Math.PI * c.radius() * c.radius();
case Rectangle r -> r.w() * r.h();
};
}
public static void main(String[] args) {
System.out.println(formatValue(42)); // 正整数: 42
System.out.println(formatValue(-5)); // 负整数: -5
System.out.println(formatValue("hello")); // 字符串: hello
System.out.println(formatValue(null)); // null 值
System.out.println("圆面积: " + area(new Circle(5))); // 78.54
System.out.println("矩形面积: " + area(new Rectangle(3, 4))); // 12.0
}
}
switch 支持的类型
| 类型 | 最低 JDK 版本 | 示例 |
|---|---|---|
int / Integer | 1.0 | switch (1) |
char / Character | 1.0 | switch ('A') |
byte / short | 1.0 | 自动提升为 int |
String | 7 | switch ("hello") |
enum | 5 | switch (Color.RED) |
| 模式匹配 | 21 | switch (obj) |
for 循环
传统 for 循环
public class ForDemo {
public static void main(String[] args) {
// 基本 for
for (int i = 0; i < 10; i++) {
System.out.print(i + " ");
}
System.out.println();
// 多变量
for (int i = 0, j = 10; i < j; i++, j--) {
System.out.println("i=" + i + ", j=" + j);
}
// 无限循环
int count = 0;
for (;;) {
if (++count > 5) break;
System.out.println("循环 " + count);
}
// 倒序
for (int i = 10; i >= 0; i--) {
System.out.print(i + " ");
}
}
}
增强 for 循环(for-each)
import java.util.*;
public class ForEachDemo {
public static void main(String[] args) {
// 数组遍历
int[] nums = {1, 2, 3, 4, 5};
for (int n : nums) {
System.out.print(n + " ");
}
System.out.println();
// List 遍历
List<String> fruits = List.of("苹果", "香蕉", "橘子");
for (String fruit : fruits) {
System.out.println("水果: " + fruit);
}
// Map 遍历
Map<String, Integer> scores = Map.of("张三", 90, "李四", 85, "王五", 92);
for (var entry : scores.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
// 带索引遍历(JDK 21+ SequencedCollection)
List<String> list = new ArrayList<>(List.of("A", "B", "C"));
for (var it = list.iterator(); it.hasNext();) {
int idx = 0;
System.out.println(idx++ + ": " + it.next());
}
// 使用传统 for 带索引
for (int i = 0; i < list.size(); i++) {
System.out.println(i + ": " + list.get(i));
}
}
}
while 循环
public class WhileDemo {
public static void main(String[] args) {
// while 循环
int i = 0;
while (i < 5) {
System.out.print(i + " ");
i++;
}
System.out.println();
// do-while 循环(至少执行一次)
int j = 10;
do {
System.out.print(j + " ");
j--;
} while (j > 5);
System.out.println();
// 读取输入
java.util.Scanner scanner = new java.util.Scanner(System.in);
String input = "";
while (!input.equals("quit")) {
System.out.print("输入命令 (quit退出): ");
input = scanner.nextLine();
System.out.println("你输入了: " + input);
}
}
}
break 与 continue
public class BreakContinueDemo {
public static void main(String[] args) {
// break —— 跳出当前循环
for (int i = 0; i < 10; i++) {
if (i == 5) break;
System.out.print(i + " "); // 0 1 2 3 4
}
System.out.println();
// continue —— 跳过本次迭代
for (int i = 0; i < 10; i++) {
if (i % 2 == 0) continue; // 跳过偶数
System.out.print(i + " "); // 1 3 5 7 9
}
System.out.println();
// 带标签的 break(跳出外层循环)
outer:
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
if (i * 5 + j > 12) break outer;
System.out.printf("(%d,%d) ", i, j);
}
}
System.out.println();
// 带标签的 continue
skip:
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (j == 1) continue skip;
System.out.printf("(%d,%d) ", i, j);
}
}
System.out.println();
}
}
循环控制最佳实践
| 场景 | 推荐方式 | 说明 |
|---|---|---|
| 知道次数 | for | 如 for (int i = 0; i < n; i++) |
| 不知道次数 | while | 如 while (scanner.hasNext()) |
| 至少执行一次 | do-while | 如菜单循环 |
| 遍历集合/数组 | for-each | 语法简洁,避免越界 |
| 需要索引 | 传统 for | 或使用 AtomicInteger |
| 无限循环 | for(;;) 或 while(true) | 用 break 退出 |
实用模式示例
import java.util.*;
public class LoopPatterns {
public static void main(String[] args) {
// 模式1: 查找第一个满足条件的元素
List<Integer> numbers = List.of(1, 3, 5, 8, 9, 12);
Integer firstEven = null;
for (int n : numbers) {
if (n % 2 == 0) {
firstEven = n;
break;
}
}
System.out.println("第一个偶数: " + firstEven); // 8
// 模式2: 收集满足条件的元素
List<Integer> evens = new ArrayList<>();
for (int n : numbers) {
if (n % 2 == 0) evens.add(n);
}
System.out.println("偶数列表: " + evens); // [8, 12]
// 模式3: 统计
int count = 0;
for (int n : numbers) {
if (n > 5) count++;
}
System.out.println("大于5的个数: " + count); // 3
// 模式4: 求和 / 最大值
int sum = 0, max = Integer.MIN_VALUE;
for (int n : numbers) {
sum += n;
max = Math.max(max, n);
}
System.out.println("总和: " + sum + ", 最大值: " + max);
// 模式5: 反转遍历
List<String> items = new ArrayList<>(List.of("A", "B", "C", "D"));
for (int i = items.size() - 1; i >= 0; i--) {
System.out.print(items.get(i) + " ");
}
System.out.println(); // D C B A
}
}
⚠️ 注意事项
- switch 忘记 break — 传统写法容易导致 case 穿透,推荐使用箭头语法。
- 循环中修改集合 — 遍历时删除元素会抛
ConcurrentModificationException,使用Iterator.remove()。 - 浮点数循环 — 避免
for (double d = 0.0; d != 1.0; d += 0.1),可能永远不停。 - 无限循环务必有退出条件 — 确保循环体中存在
break或条件能变为false。
💡 技巧
提前返回减少嵌套:
// ❌ 深嵌套 if (user != null) { if (user.isActive()) { if (user.hasPermission()) { doSomething(); } } } // ✅ 提前返回 if (user == null) return; if (!user.isActive()) return; if (!user.hasPermission()) return; doSomething();使用 Stream 替代简单循环(JDK 8+):
List<Integer> evens = numbers.stream() .filter(n -> n % 2 == 0) .toList();for-each 不能修改数组元素 — 因为循环变量是拷贝,修改不影响原数组。
🏢 业务场景
- 状态机: 使用
while循环 +switch实现订单状态流转。 - 数据校验: 多条件
if-else if链实现复杂业务规则。 - 菜单系统:
do-while循环实现交互式命令行程序。 - 批量处理:
for循环遍历数据列表,逐条处理业务逻辑。