Java流程控制全解析:从基础到高级,掌握程序执行的脉络

引言

流程控制是编程语言的基石,它决定了代码执行的顺序路径。Java提供了强大而灵活的流程控制语句,使你能够根据条件执行代码、重复执行任务以及跳出循环。掌握这些结构是写出高效、逻辑清晰程序的关键。

一、分支结构

1、if语句

  • 语法:

    java 复制代码
    if (condition) {
        // 当 condition 为 true 时执行的代码块
    }
  • 执行流程:

    1. 计算 condition (必须是一个布尔表达式:truefalse)
    2. 如果结果为 true,则执行代码块内的语句
    3. 如果结果为 false,则跳过代码块,继续执行后面的代码
  • 示例:

    java 复制代码
    int age = 18;
    if (age >= 18) {
        System.out.println("你已成年。");
    }
    // 无论 age 是否 >=18, 这行都会执行
    System.out.println("年龄检查完毕。");

2、if-else语句

  • 语法:

    java 复制代码
    if (condition) {
        // 当 condition 为 true 时执行的代码块
    } else {
        // 当 condition 为 false 时执行的代码块
    }
  • 执行流程:

    1. 计算 condition
    2. 如果 true,执行 if 代码块
    3. 如果 false,执行 else 代码块
    4. 两个代码块必选其一执行,且只执行其一
  • 示例:

    java 复制代码
    int score = 75;
    if (score >= 60) {
        System.out.println("及格!");
    } else {
        System.out.println("不及格!");
    }

3、if-else-if阶梯

  • 语法:

    java 复制代码
    if (condition1) {
        // condition1 为 true 时执行
    } else if (condition2) {
        // condition1 为 false 且 condition2 为 true 时执行
    } else if (condition3) {
        // 前面条件都为 false 且 condition3 为 true 时执行
    } else {
        // 所有条件都为 false 时执行 (可选)
    }
  • 执行流程:

    1. 按顺序检查每个 condition
    2. 遇到第一个为 truecondition,则执行其对应的代码块,然后跳过整个 if-else-if 结构剩余部分
    3. 如果所有 condition 都为 false,则执行 else 块(如果存在);如果不存在 else,则整个结构不执行任何操作
  • 示例:

    java 复制代码
    int grade = 85;
    if (grade >= 90) {
        System.out.println("优秀 (A)");
    } else if (grade >= 80) { // 隐含 grade < 90
        System.out.println("良好 (B)");
    } else if (grade >= 70) { // 隐含 grade < 80
        System.out.println("中等 (C)");
    } else if (grade >= 60) { // 隐含 grade < 70
        System.out.println("及格 (D)");
    } else {
        System.out.println("不及格 (F)");
    }

4、switch语句 (传统与现代)

基于一个表达式的值,从多个可能的执行路径中选择一个。适用于多分支选择,尤其当分支基于单个变量或表达式的离散值(==整数、字符、字符串 String、枚举 enum==)时,通常比 if-else-if 更清晰。

4.1、传统语法 (Java 7 及之前,注意break)

java 复制代码
switch (expression) {
    case value1:
        // expression 等于 value1 时执行的语句
        break; // 跳出 switch 块
    case value2:
        // expression 等于 value2 时执行的语句
        break;
    ... // 可以有任意多个 case
    default:
        // 如果 expression 不匹配任何 case 值时执行的语句 (可选)
}
  • expression:可以是 byte, short, int, char (Java 7之前),以及 String (Java 7+), enum

  • case valueNvalueN 必须是常量表达式,且类型必须与 expression 兼容。每个 case 代表一个可能匹配的值

  • break:至关重要!它终止当前 case 的执行并跳出整个 switch 块。如果省略 break,程序会继续执行下一个 case 中的语句(无论其值是否匹配),这称为"case穿透(fall-through)"。除非有意设计穿透,否则必须写 break

  • default:可选的。当没有 case 匹配时执行。可以放在任何位置(开头、中间、结尾),但通常放结尾。不需要 break(如果它是最后一个)

  • 示例 (传统带break):

    java 复制代码
    int dayOfWeek = 3;
    switch (dayOfWeek) {
        case 1:
            System.out.println("星期一");
            break;
        case 2:
            System.out.println("星期二");
            break;
        case 3:
            System.out.println("星期三");
            break;
        case 4:
            System.out.println("星期四");
            break;
        case 5:
            System.out.println("星期五");
            break;
        default:
            System.out.println("周末或无效日期");
    } // 输出: 星期三
  • 示例 (故意 Case 穿透):

    java 复制代码
    char grade = 'B';
    switch (grade) {
        case 'A':
        case 'B': // A 或 B 都执行下面的代码
            System.out.println("成绩优良");
            break;
        case 'C':
            System.out.println("成绩中等");
            break;
        case 'D':
        case 'F': // D 或 F 都执行下面的代码
            System.out.println("需要努力");
            break;
        default:
            System.out.println("无效成绩");
    } // 输出: 成绩优良

4.2、现代语法 (Java 12+, 使用->箭头和yield)

Java 12 引入了更简洁、更安全(避免意外穿透)的 switch 表达式和语句形式::

  • 箭头标签 (case L ->):使用 -> 代替 :。如果标签匹配,则只执行 -> 右侧的表达式或语句块

  • 多值匹配 (case L1, L2 ->):一个 case 可以匹配多个值,用逗号分隔

  • switch 表达式 (返回值):整个 switch 可以作为一个表达式,使用 yield 返回一个值。必须覆盖所有可能情况(或 default

  • 示例 (现代 switch 语句,无穿透):

    java 复制代码
    int dayOfWeek = 3;
    switch (dayOfWeek) {
        case 1 -> System.out.println("星期一"); // 单条语句可直接写
        case 2 -> System.out.println("星期二");
        case 3 -> {
            // 多条语句用代码块 {}
            System.out.println("星期三");
            System.out.println("一周的中点!");
        }
        case 4, 5 -> System.out.println("临近周末"); // 匹配 4 或 5
        default -> System.out.println("周末或无效日期");
    } // 输出: 星期三 \n 一周的中点!
  • 示例 (switch 表达式,使用 yield 返回值,类似于return):

    java 复制代码
    int dayOfWeek = 3;
    String dayType = switch (dayOfWeek) {
        case 1, 2, 3, 4, 5 -> "工作日";
        case 6, 7 -> {
            // 代码块中使用 yield 返回值
            System.out.println("放假了...");
            yield "周末"; // yield 提供 switch 表达式的返回值
        }
        default -> {
            // 代码块中使用 yield 返回值
            System.out.println("无效输入: " + dayOfWeek);
            yield "未知"; // yield 提供 switch 表达式的返回值
        }
    }; // 注意:作为表达式,末尾有分号 ';'
    System.out.println(dayOfWeek + " 是 " + dayType); // 输出: 3 是 工作日

4.3、更高级语法 (Java 17+, 模式匹配预览特性)

Java 17 开始引入对 switch 语句的新特性模式匹配,作为预览功能提供。这种特性允许在 switch 的 case 分支中直接进行类型判断绑定变量,从而让代码更简洁、更安全。

java 复制代码
static String test(Object obj) {
    return switch (obj) {
        case String s -> "字符串: " + s;
        case Integer i -> "整数: " + i;
        case null -> "空值";
        default -> "其他类型";
    };
}
  • case String s -> ...:如果 obj 是一个字符串,就匹配并将其绑定到变量 s
  • case Integer i -> ...:同理,匹配整数
  • case null -> ...:甚至可以对 null 值进行单独处理
  • default -> ...:兜底处理其他类型

注意⚠️:这是预览功能:意味着它还不是 Java 标准的一部分,将来可能会改动,从 Java 21 开始,这一功能有望正式成为标准

二、循环结构

1、for循环

  • 用途:当循环次数已知或在循环前就知道初始化、条件和迭代步骤时特别适用。结构清晰

  • 传统语法:

    java 复制代码
    for (initialization; condition; iteration) {
        // 循环体:当 condition 为 true 时重复执行的代码
    }
    • initialization (初始化):在循环开始前执行一次。通常用于声明和初始化循环控制变量 (如:int i = 0;)
    • condition (条件):每次循环迭代检查的布尔表达式。如果 true,执行循环体;如果 false,终止循环
    • iteration (迭代/步进):每次循环体执行执行。通常用于更新循环控制变量 (如:i++, i = i + 2)
  • 执行流程:

    1. 执行 initialization (仅一次)
    2. 计算 condition
    3. 如果 conditiontrue
      • 执行循环体
      • 执行 iteration
      • 回到步骤 2 (再次检查 condition)
    4. 如果 conditionfalse,循环终止
  • 示例:

    java 复制代码
    // 打印 0 到 9
    for (int i = 0; i < 10; i++) {
        System.out.println(i);
    }
    // 计算 1 到 100 的和
    int sum = 0;
    for (int num = 1; num <= 100; num++) {
        sum += num;
    }
    System.out.println("Sum: " + sum);
  • 格式的多样性(多变量控制省略部分语句

    java 复制代码
    // 省略部分语句(但必须保留分号)
    int i = 0;
    for ( ; i < 5; i++) {
        System.out.println(i);
    }
    
    // 多个变量用逗号隔开
    for (int i = 0, j = 10; i < j; i++, j--) {
        System.out.println("i = " + i + ", j = " + j);
    }

2、while循环

  • 用途:当循环次数未知,但在循环开始前有一个明确的继续条件时适用。先判断条件,再决定是否执行循环体

  • 语法:

    java 复制代码
    while (condition) {
        // 循环体:当 condition 为 true 时重复执行的代码
    }
  • 执行流程:

    1. 计算 condition
    2. 如果 conditiontrue
      • 执行循环体
      • 回到步骤 1 (再次检查 condition)
    3. 如果 conditionfalse,循环终止
  • 特点:循环体可能一次都不执行(如果初始条件就是 false

  • 示例:

    java 复制代码
    int i = 0;
    while (i < 5) {
       System.out.println(i);
       i++;
    }

3、do-while循环

  • 用途:当循环体至少需要执行一次,然后再根据条件决定是否继续时适用。先执行一次循环体,再判断条件

  • 语法:

    java 复制代码
    do {
        // 循环体:至少执行一次
    } while (condition); // 注意结尾的分号
  • 执行流程:

    1. 执行循环体
    2. 计算 condition
    3. 如果 conditiontrue,回到步骤 1
    4. 如果 conditionfalse,循环终止
  • 特点:循环体至少执行一次

  • 示例:

    java 复制代码
    // 1.基本用法
    int i = 0;
    do {
        System.out.println(i);
        i++;
    } while (i < 5);
    
    // 2.条件为假也执行一次
    int i = 10;
    do {
        System.out.println("i = " + i);  // 会执行一次
        i++;
    } while (i < 5);

4、增强for循环 (for-each)

  • 用途:专门用于遍历数组实现了 Iterable 接口的集合 (如 List, Set, Queue)。语法简洁,避免了显式索引操作

  • 语法:

    java 复制代码
    for (ElementType element : collectionOrArray) {
        // 使用 element 执行操作
    }
    • ElementType:集合或数组中元素的类型
    • element:循环变量,在每次迭代中依次被赋值为集合或数组中的当前元素
    • collectionOrArray:要遍历的数组集合对象
  • 执行流程:自动依次从数组或集合中取出每个元素,赋值给 element,并执行循环体。遍历完所有元素后结束

  • 优点:简洁、安全(无需管理索引)、不易出错(避免索引越界)

  • 缺点:不能直接访问当前元素的索引;不能修改集合结构(如删除元素,否则可能引发 ConcurrentModificationException);只能单向顺序遍历

  • 示例:

    java 复制代码
    // 1.遍历数组
    int[] numbers = {1, 2, 3, 4, 5};
    for (int num : numbers) {
        System.out.print(num + " ");
    } // 输出: 1 2 3 4 5
    
    // 2.遍历 List 集合
    List<String> fruits = Arrays.asList("Apple", "Banana", "Orange");
    for (String fruit : fruits) {
        System.out.println(fruit);
    } // 输出: Apple \n Banana \n Orange

三、流程控制的利器:break和continue

1、break语句

  • 用途:

    • 在循环中 (for, while, do-while):立即终止其所在的最内层循环,跳出循环体,继续执行循环之后的代码
    • switch 中:终止 case 的执行并跳出整个 switch 块(防止穿透)
  • 示例 (跳出循环):

    java 复制代码
    // 查找数组中第一个负数
    int[] nums = {5, 8, -2, 10, 3};
    boolean found = false;
    for (int num : nums) {
        if (num < 0) {
            System.out.println("找到负数: " + num);
            found = true;
            break; // 找到第一个负数后立即跳出循环
        }
    }
    if (!found) {
        System.out.println("没有找到负数");
    }

2、continue语句

  • 用途:仅用于循环中跳过当前迭代中循环体内 continue 语句之后的所有代码,立即进入下一次迭代(检查循环条件并执行步进语句)

  • 示例:

    java 复制代码
    // 打印 1 到 10 的奇数
    for (int i = 1; i <= 10; i++) {
        if (i % 2 == 0) { // 如果是偶数
            continue; // 跳过本次循环剩余部分,直接 i++ 然后检查 i<=10
        }
        System.out.println(i); // 只有奇数会执行到这里
    }
    // 输出: 1 \n 3 \n 5 \n 7 \n 9

3、带标签的break和continue(谨慎使用)

  • 用途:用于跳出多层嵌套的循环或语句块

  • 语法:在目标循环或语句块放置一个标签 (label:), 然后在 breakcontinue 后指定该标签名 (break label; / continue label;)

  • break label;:立即终止标签所标记的整个循环或语句块

  • continue label;:立即跳转到标签所标记的循环的下一次迭代开始处(跳过标记循环当前迭代的剩余部分)

  • 示例 (跳出外层循环):

    java 复制代码
    outerLoop: // 标签定义在外层 for 循环前
    for (int i = 0; i < 5; i++) {
        innerLoop: // 标签定义在内层 for 循环前
        for (int j = 0; j < 5; j++) {
            System.out.println("i=" + i + ", j=" + j);
            if (i == 2 && j == 2) {
                break outerLoop; // 跳出整个 outerLoop (两层循环都终止)
            }
        }
    }
    // 当 i=2, j=2 时输出终止,后续 i=3,4 都不再执行

注意:带标签的break/continue会破坏代码结构,使逻辑不易追踪。优先考虑重构代码(如将内层循环提取为方法)来避免使用它们。仅在逻辑清晰且必要时使用。

四、无限循环与空语句

1、无限循环

  • 定义:循环条件始终为 true 的循环,理论上会一直执行下去

  • 常见形式:

    java 复制代码
    // while 形式
    while (true) {
        // ... 需要某种 break 条件跳出 ...
    }
    // for 形式
    for (;;) { // 初始化、条件、迭代都省略
        // ... 需要某种 break 条件跳出 ...
    }
  • 用途:服务器监听、游戏主循环、需要用户主动退出的程序等。必须在循环体内提供跳出机制(如 break, return, System.exit()

  • 风险:如果缺少跳出机制,程序将永远挂起,消耗CPU资源

2、空语句

  • 定义:一个单独的分号 ; 表示一条不执行任何操作的语句

  • 在流程控制中的潜在陷阱:

    java 复制代码
    // 意图:i<10 时才打印 i
    int i = 0;
    while (i < 10); // 注意这里错误地多了一个分号!这是一个空语句循环体。
    {
        System.out.println(i); // 这行代码在 while 循环块之外!
        i++;
    }
    // 结果:while (i < 10); 是一个无限循环(如果 i<10),因为循环体是空语句 `;`。
    //       { ... } 只是一个普通的代码块,在无限循环之后(永远执行不到)。

警示:在 if, for, while 的条件后切勿随意加分号 ;,除非你明确需要一个空循环体。这通常是逻辑错误

总结

Java的流程控制语句(分支:if, switch;循环:for, while, do-while, for-each;跳转:break, continue)为你提供了构建程序逻辑的完整工具箱。理解每种结构的语法、执行流程、适用场景和潜在陷阱,并结合清晰编码的最佳实践,是编写健壮、高效、易于维护的Java程序的基础。

相关推荐
bug攻城狮6 分钟前
Spring Boot Banner
java·spring boot·后端
MadPrinter33 分钟前
SpringBoot学习日记 Day11:博客系统核心功能深度开发
java·spring boot·后端·学习·spring·mybatis
dasseinzumtode33 分钟前
nestJS 使用ExcelJS 实现数据的excel导出功能
前端·后端·node.js
淦出一番成就36 分钟前
Java反序列化接收多种格式日期-JsonDeserialize
java·后端
Java中文社群38 分钟前
Hutool被卖半年多了,现状是逆袭还是沉寂?
java·后端
程序员蜗牛1 小时前
9个Spring Boot参数验证高阶技巧,第8,9个代码量直接减半!
后端
yeyong1 小时前
咨询kimi关于设计日志告警功能,还是有启发的
后端
库森学长1 小时前
2025年,你不能错过Spring AI,那个汲取了LangChain灵感的家伙!
后端·openai·ai编程
Java水解2 小时前
Spring Boot 启动流程详解
spring boot·后端
学历真的很重要2 小时前
Claude Code Windows 原生版安装指南
人工智能·windows·后端·语言模型·面试·go