强曰为道

与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

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 / Integer1.0switch (1)
char / Character1.0switch ('A')
byte / short1.0自动提升为 int
String7switch ("hello")
enum5switch (Color.RED)
模式匹配21switch (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();
    }
}

循环控制最佳实践

场景推荐方式说明
知道次数forfor (int i = 0; i < n; i++)
不知道次数whilewhile (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
    }
}

⚠️ 注意事项

  1. switch 忘记 break — 传统写法容易导致 case 穿透,推荐使用箭头语法。
  2. 循环中修改集合 — 遍历时删除元素会抛 ConcurrentModificationException,使用 Iterator.remove()
  3. 浮点数循环 — 避免 for (double d = 0.0; d != 1.0; d += 0.1),可能永远不停。
  4. 无限循环务必有退出条件 — 确保循环体中存在 break 或条件能变为 false

💡 技巧

  1. 提前返回减少嵌套

    // ❌ 深嵌套
    if (user != null) {
        if (user.isActive()) {
            if (user.hasPermission()) {
                doSomething();
            }
        }
    }
    // ✅ 提前返回
    if (user == null) return;
    if (!user.isActive()) return;
    if (!user.hasPermission()) return;
    doSomething();
    
  2. 使用 Stream 替代简单循环(JDK 8+):

    List<Integer> evens = numbers.stream()
        .filter(n -> n % 2 == 0)
        .toList();
    
  3. for-each 不能修改数组元素 — 因为循环变量是拷贝,修改不影响原数组。

🏢 业务场景

  • 状态机: 使用 while 循环 + switch 实现订单状态流转。
  • 数据校验: 多条件 if-else if 链实现复杂业务规则。
  • 菜单系统: do-while 循环实现交互式命令行程序。
  • 批量处理: for 循环遍历数据列表,逐条处理业务逻辑。

📖 扩展阅读