4. 流程控制语句:if-else、switch、for、while、do-while循环、break与continue的使用

流程控制语句是Java程序实现逻辑判断与重复操作的核心语法机制。在《计算机二级Java程序设计》考试中,流程控制不仅涉及语法正确性,更考查逻辑组织能力与边界条件处理。本章将系统讲解选择结构(if-else、switch)与循环结构(for、while、do-while)的语法规则、执行流程、适用场景,以及break与continue对循环行为的干预方式。掌握这些语句的本质区别与嵌套技巧,是编写健壮、高效Java程序的基础。

Java流程控制语句知识框架 选择结构(条件判断) if-else 系列 if / if-else / if-else if-else 条件为boolean表达式 适合区间、复合条件判断 switch 语句 等值匹配(byte/short/int/ char/String/枚举) 支持case穿透与default 循环结构(重复执行) for 初始化;条件;迭代 适合已知循环次数 计数器控制 while 先判断后执行 可能0次执行 条件控制 do-while 先执行后判断 至少执行1次 条件控制 跳转语句(循环控制) break:终止当前循环/switch continue:跳过本次循环剩余语句 嵌套规则与注意事项 if/switch可嵌套循环;循环可相互嵌套;break/continue只作用于最近一层循环 避免死循环:确保循环条件在循环体内能够被改变

4.1 选择结构:if-else与switch

4.1.1 核心原理

选择结构根据条件表达式的布尔结果决定程序执行路径。if-else语句适用于区间判断、复合逻辑(与或非)以及需要灵活条件组合的场景;switch语句则专用于等值匹配,其底层使用跳转表实现,在分支较多且判断值为离散常量时执行效率更高。Java 7之后switch支持String类型,Java 14起引入switch表达式(箭头语法),但二级考试仍以经典switch语句为主。

4.1.2 语法与判断方法

// if-else 三种形式
if (条件) { /* 条件为true时执行 */ }

if (条件) { /* true分支 */ } else { /* false分支 */ }

if (条件1) { /* 分支1 */ } 
else if (条件2) { /* 分支2 */ } 
else { /* 兜底分支 */ }

// switch 经典语法
switch (表达式) {
    case 值1: 语句; break;
    case 值2: 语句; break;
    default: 语句; break;  // 可选
}

判断方法要点:

  • if-else选择依据:条件表达式必须是boolean类型,不能直接写数字(如if(1)错误);else if按顺序从上到下匹配,一旦命中即跳出整个if-else链。
  • switch选择依据:表达式类型限byte/short/int/char/String/枚举;case值必须是编译期常量,且不能重复;省略break会产生case穿透,即继续执行后续case直到遇到break或switch结束。
  • 嵌套注意:else总是与最近的未配对if结合(悬空else问题),建议使用大括号明确层级。

4.1.3 案例拆解:成绩等级评定

某高校成绩评定规则:90-100为A,80-89为B,70-79为C,60-69为D,60以下为E。要求输入成绩(0-100整数),输出对应等级。

int score = 85;
// 方案一:if-else if 链(适合区间判断)
if (score >= 90) {
    System.out.println("A");
} else if (score >= 80) {
    System.out.println("B");
} else if (score >= 70) {
    System.out.println("C");
} else if (score >= 60) {
    System.out.println("D");
} else {
    System.out.println("E");
}

// 方案二:switch(需先转换为等级段)
int level = score / 10;  // 整除取十位
switch (level) {
    case 10:
    case 9:  System.out.println("A"); break;
    case 8:  System.out.println("B"); break;
    case 7:  System.out.println("C"); break;
    case 6:  System.out.println("D"); break;
    default: System.out.println("E"); break;
}

案例复盘:方案一逻辑直观,适合区间判断;方案二利用整除将连续区间映射为离散值,利用case穿透合并10和9两个分支,代码更紧凑。实际开发中,若判断条件为区间,优先if-else;若为固定离散值(如菜单选项、状态码),优先switch。注意方案二未处理score超出0-100的异常输入,生产环境需增加合法性校验。

常见误区:① 在if条件中使用赋值运算符=而非等值判断==,导致条件恒为true;② switch中遗漏break造成意外穿透;③ case值使用变量(非常量)导致编译错误;④ 浮点数直接比较相等(如if (x == 0.1))因精度问题可能判断失败。

4.2 循环结构:for、while与do-while

4.2.1 核心原理

循环结构用于重复执行一段代码块,直到循环条件不再满足。for循环将初始化、条件判断、迭代更新集中在头部,适合已知循环次数的场景;while循环先判断条件再执行,适合循环次数未知但终止条件明确的场景;do-while循环先执行一次再判断,保证循环体至少执行一次,适合“至少需要执行一次”的业务逻辑(如菜单显示、用户输入校验)。

4.2.2 语法对比与选择方法

循环类型 语法结构 执行次数 适用场景
for for(初始化; 条件; 迭代){ } 0~N次(条件初始为false则0次) 遍历数组/集合、固定次数计数
while while(条件){ } 0~N次(先判断) 读取文件直到EOF、等待用户输入特定值
do-while do{ }while(条件); 至少1次 菜单循环显示、先执行后验证

选择判断流程:

  1. 若循环次数由计数器或数组长度明确决定,选择for循环。
  2. 若循环次数未知,但存在明确的终止条件(如输入特定字符退出),选择while循环。
  3. 若循环体必须至少执行一次(如先显示菜单再询问用户是否继续),选择do-while循环。

4.2.3 案例拆解:数字累加与死循环排查

场景:计算1到100之间所有偶数的和,并输出结果。要求分别用三种循环实现,并分析各自的边界处理。

// for实现
int sumFor = 0;
for (int i = 2; i <= 100; i += 2) {
    sumFor += i;
}
System.out.println("for结果: " + sumFor);

// while实现
int sumWhile = 0;
int j = 2;
while (j <= 100) {
    sumWhile += j;
    j += 2;
}
System.out.println("while结果: " + sumWhile);

// do-while实现
int sumDo = 0;
int k = 2;
do {
    sumDo += k;
    k += 2;
} while (k <= 100);
System.out.println("do-while结果: " + sumDo);

分析过程:三种循环均从2开始,步长为2,终止条件为i <= 100。for循环将迭代变量i的作用域限制在循环内部,避免外部误用;while和do-while需要手动维护迭代变量j和k,且循环结束后变量仍保留。do-while在此场景中与while结果一致,因为初始值2满足条件,循环体必然执行。若初始值改为101,while循环0次执行,do-while仍执行1次(累加101),体现两者本质差异。

死循环排查要点:① 检查循环条件是否在循环体内被更新(如遗漏i++);② 检查条件是否永远为true(如while(true)但无break出口);③ 浮点数循环变量因精度问题可能无法精确到达终止值;④ 嵌套循环中内层循环修改了外层循环的迭代变量。

4.3 break与continue:循环的精确控制

4.3.1 核心原理

break用于立即终止当前所在循环或switch语句,程序跳转到循环外的下一条语句;continue用于跳过当前循环迭代中剩余的代码,直接进入下一次迭代的条件判断。两者均只作用于最近一层的循环结构,若需跳出多层嵌套循环,可使用带标签的break(如outer: for(...){ ... break outer; })。

4.3.2 使用规则与操作流程

  • break使用场景:在循环中搜索到目标元素后提前退出,避免无效迭代;在switch中防止case穿透。
  • continue使用场景:跳过不符合条件的元素(如只处理奇数),或跳过循环体尾部的某些操作。
  • 标签语法:标签名: 循环语句,break/continue后跟标签名可跳转到指定层。
// 示例:查找数组中第一个大于50的数并输出其索引
int[] arr = {12, 45, 67, 89, 23};
int targetIndex = -1;
for (int i = 0; i < arr.length; i++) {
    if (arr[i] > 50) {
        targetIndex = i;
        break;  // 找到后立即终止循环
    }
}
System.out.println("第一个大于50的索引: " + targetIndex);

// 示例:输出1-10中所有奇数(跳过偶数)
for (int i = 1; i <= 10; i++) {
    if (i % 2 == 0) {
        continue;  // 跳过偶数,不执行后续打印
    }
    System.out.print(i + " ");
}
// 输出: 1 3 5 7 9

4.3.3 案例拆解:素数检测与嵌套循环控制

场景:输出2到50之间的所有素数。要求使用嵌套循环,内层循环判断是否为素数,外层循环遍历候选数字,并利用break优化性能。

for (int num = 2; num <= 50; num++) {
    boolean isPrime = true;
    // 只需检查到sqrt(num)即可,减少循环次数
    for (int divisor = 2; divisor <= Math.sqrt(num); divisor++) {
        if (num % divisor == 0) {
            isPrime = false;
            break;  // 已确定非素数,立即终止内层循环
        }
    }
    if (isPrime) {
        System.out.print(num + " ");
    }
}
// 输出: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47

案例复盘:内层循环使用break在发现第一个因子时立即退出,避免继续检查更大的除数,时间复杂度从O(n²)优化为O(n√n)。外层循环通过isPrime标志位判断是否打印。此案例展示了break在嵌套循环中的典型应用——提前终止内层循环,同时外层循环继续执行。若需同时终止外层循环,则需使用带标签的break。

经验总结:① break与continue后不能直接跟其他语句(不可达代码编译错误);② 在switch中使用continue是非法的(continue仅用于循环);③ 嵌套循环中,break/continue默认作用于最内层循环,使用标签可精确控制跳转层级;④ 过度使用break/continue会降低代码可读性,建议将复杂循环逻辑提取为独立方法。

4.4 综合对比与应试要点

对比维度 if-else switch for while do-while
判断条件类型 boolean表达式 等值匹配(int/String等) boolean表达式(循环条件)
执行次数 单次分支 单次分支 0~N次 0~N次 至少1次
典型应用 区间判断、复合条件 菜单选择、状态机 数组遍历、计数 条件循环、文件读取 先执行后验证
break作用 不适用 防止穿透 终止当前循环
continue作用 不适用 不适用 跳过本次迭代剩余语句

二级考试高频考点:

  • if-else的悬空else问题:else与最近的if配对。
  • switch的case穿透现象:省略break时,后续case会依次执行。
  • for循环的初始化表达式可省略,但分号不能省略(for(;;)为死循环)。
  • while与do-while的区别:do-while末尾必须有分号。
  • break与continue在嵌套循环中的作用层级。
  • 循环变量作用域:for循环内定义的变量在循环外不可访问。
易错题警示:① for(int i=0; i<10; i++){ if(i==5) continue; System.out.println(i); }输出0-9中除5以外的数字,共9个;② while(false){ }不执行循环体,但do{ }while(false);执行一次;③ switch中default位置可放在任意位置,但通常放在最后;④ 循环条件中比较浮点数时,应使用差值值小于阈值的方式判断。

4.5 实战综合案例:简易ATM取款机逻辑

背景与约束:模拟ATM取款流程,初始余额1000元。要求:用户输入取款金额,若金额大于余额则提示错误并重新输入;若金额为负数或0则提示非法;每次取款后显示剩余余额;用户输入0时退出系统。需使用do-while保证至少显示一次菜单,使用while处理非法输入,使用break退出循环。

import java.util.Scanner;

public class ATMSimulator {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        double balance = 1000.0;
        int choice;
        
        do {
            System.out.println("当前余额: " + balance);
            System.out.println("请输入取款金额(输入0退出): ");
            choice = scanner.nextInt();
            
            if (choice == 0) {
                break;  // 退出循环
            }
            
            if (choice < 0) {
                System.out.println("金额不能为负数!");
                continue;  // 跳过本次迭代,重新输入
            }
            
            if (choice > balance) {
                System.out.println("余额不足!");
                continue;
            }
            
            balance -= choice;
            System.out.println("取款成功,剩余余额: " + balance);
            
        } while (true);  // 通过break控制退出
        
        System.out.println("感谢使用,再见!");
        scanner.close();
    }
}

案例拆解:

  • 初始现象:用户可能输入非法金额(负数、超余额),需要循环校验。
  • 关键设计:do-while保证菜单至少显示一次;break在输入0时立即退出;continue跳过非法输入后的余额扣减逻辑。
  • 风险与代价:若用户持续输入非法值,循环不会退出,需提供明确的退出方式(输入0)。
  • 复盘经验:循环控制语句的合理组合能实现清晰的用户交互逻辑。实际ATM系统还需考虑超时退出、交易记录等,此处仅演示核心流程控制。

流程控制语句是Java程序逻辑的骨架,熟练掌握if-else、switch、for、while、do-while以及break、continue的组合运用,能够应对绝大多数编程场景。在考试中,建议先画出逻辑流程图再编写代码,注意边界条件(如0次循环、首次执行、临界值)的测试。通过本章的案例拆解与对比表格,考生应能准确判断不同场景下的最优语句选择,并规避常见的语法陷阱。