Java · 第 3 章

第 3 章 流程控制

if/else 与 switch(含穿透陷阱);for/while/do-while/foreach 适用场景;break、continue 与标签;综合示例:判断素数。

3.1 分支结构:if 与 switch

选择结构的考点集中在:写法、配对、switch 穿透。

// ① 单分支 / 双分支 / 多分支
if (score >= 60) {
    System.out.println("及格");
} else if (score >= 40) {
    System.out.println("补考");
} else {
    System.out.println("重修");
}

// ② switch(JDK 7+ 支持 String)
switch (day) {
    case 1:
        System.out.println("周一");
        break;                 // ← 没有 break 会「穿透」到下一个 case
    case 2:
        System.out.println("周二");
        break;
    default:
        System.out.println("其他");
}
三条铁律
  • else 与最近的未配对 if 配对(悬空 else 问题)——所以哪怕只有一行也建议写花括号。
  • switch 的 case 后面通常要 break,否则继续执行下一个 case(穿透);故意利用穿透可以合并多个分支。
  • switch 的表达式类型:byte/short/char/int、enum、String(JDK 7+);不支持 long、boolean、浮点。
易错
  • 把 == 写成 =:if (a = 1) 编译报错(Java 要求条件必须是 boolean,这点比 C++ 安全)。
  • 判断相等用 ==,判断字符串内容相等要用 equals(第 5 章详讲)。
  • default 可以放在任意位置,但建议放最后;没有匹配且无 default 时什么都不做。
课堂练习(3 题)
  1. switch 后面忘记写 break 会怎样? 答:发生"穿透",继续执行后续 case 的语句,直到遇到 break 或 switch 结束。
  2. 下列哪个能作为 switch 的表达式:A. long B. String C. double D. boolean 答:B(String,JDK 7+ 支持)。long、double、boolean 都不行。
  3. 把成绩转成等级(≥90 A,≥80 B,其余 C),用 else if 怎么写? 答:if (s >= 90) g = 'A'; else if (s >= 80) g = 'B'; else g = 'C';

3.2 三种循环:for / while / do-while

先记住各自适用场景,再看 break/continue。

// ① for:次数已知(最常用)
for (int i = 0; i < 10; i++) {      // 初始化; 条件; 更新
    System.out.println(i);           // i 的作用域只在循环内
}

// ② while:次数未知、先判断后执行
int n = 0;
while (n < 5) {
    n++;
}

// ③ do-while:先执行一次再判断(至少执行一次)
int k = 0;
do {
    k++;
} while (k < 3);

// ④ 增强 for(foreach):遍历数组/集合,不能改下标
int[] arr = {1, 2, 3};
for (int v : arr) {
    System.out.println(v);
}
循环适用场景执行顺序
for次数确定、需要下标初始化 → 判断 → 执行 → 更新 → 判断…
while次数不确定(读到某值停止)先判断,条件为真才执行(可能一次都不执行)
do-while至少要执行一次(如菜单交互)先执行一次,再判断(至少执行一次)
for-each只读遍历,不需要下标依次取出每个元素
易错
  • while 后面别加多余分号:while (n < 5); 会变成死循环(分号就是空语句体)。
  • for 里定义的 i 出了循环就不能用;循环外要用就先在外部声明。
  • 用 double 做循环变量或判断相等会有精度误差:for (double x = 0; x != 1; x += 0.1) 可能死循环。
课堂练习(3 题)
  1. while 与 do-while 最本质的区别是什么? 答:while 先判断后执行(可能零次),do-while 先执行一次再判断(至少一次)。
  2. 求 1+2+…+100,用 for 循环怎么写? 答:int s = 0; for (int i = 1; i <= 100; i++) s += i;(结果 5050)。
  3. for (int i = 0; i < 3; i++); System.out.println(i); 有问题吗? 答:有两处问题——for 后多了分号(循环体变空);且 i 在循环外不可见,打印 i 会编译报错。

3.3 break / continue / 标签

跳出循环的三种手段,标签是 Java 比 C++ 多的一个东西。

for (int i = 1; i <= 10; i++) {
    if (i == 3) continue;     // 跳过本次,进入下一轮
    if (i == 6) break;        // 直接结束整个循环
    System.out.print(i + " ");
}
// 输出:1 2 4 5

// 带标签的 break:一次跳出多层嵌套循环
outer:
for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
        if (i * j > 1) {
            break outer;      // 跳出 outer 标记的那一层
        }
        System.out.println(i + "," + j);
    }
}
区别一句话
  • break:结束整个循环;continue:跳过本次循环体剩余部分,直接下一轮。
  • continue 只跳过当前循环(在 for 里会先执行"更新"语句再判断)。
  • 标签写法是 标签名: 放在循环前,配合 break 标签名 / continue 标签名 用。
课堂练习(2 题)
  1. 循环 1~10,遇到 5 就跳过、遇到 8 就停止,输出序列是什么? 答:1 2 3 4 6 7(5 被 continue 跳过,8 处 break 结束)。
  2. 想在嵌套循环中直接跳出最外层,Java 提供什么机制? 答:标签(label)——在外层循环前写 outer:,内层用 break outer;。

3.4 综合示例:判断素数(把前面串起来)

一个例子练完分支+循环+break,建议自己在沙盒里敲一遍。

import java.util.Scanner;

public class Prime {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.print("请输入一个大于 1 的整数:");
        int n = sc.nextInt();

        boolean isPrime = true;
        for (int i = 2; i * i <= n; i++) {      // 只需试除到 sqrt(n)
            if (n % i == 0) {
                isPrime = false;
                break;                          // 找到因子即可停止
            }
        }

        if (isPrime) {
            System.out.println(n + " 是素数");
        } else {
            System.out.println(n + " 不是素数");
        }
        sc.close();
    }
}
这段代码里值得记住的三点
  • 循环条件写 i * i <= n 而不是 i <= Math.sqrt(n)——避免浮点运算,也更快。
  • 用 boolean 标志位记录结果,比在循环里直接打印更清晰。
  • 找到因子立刻 break,不要傻傻除到底。
易错
  • 边界:1 不是素数、2 是素数;负数和非整数输入要先判断。
  • 循环从 i = 2 开始,别从 1 开始(任何数都能被 1 整除)。

直接在 Java 在线运行环境 里跑一遍,改改数字试试。

课堂练习(3 题)
  1. 为什么试除只要到 √n 就够了? 答:若 n = a × b 且 a ≤ b,则 a ≤ √n;大于 √n 的因子必然有对应小因子已被检查到。
  2. 把上面程序改成"输出 100 以内所有素数",大致思路是什么? 答:外层循环 2~100,内层用同样的试除判断,是素数就打印(或抽成 isPrime 方法)。
  3. 输入 1 时程序会输出什么?是否符合预期? 答:循环不执行,isPrime 保持 true,输出"1 是素数"——这是错误的,需在开头加判断 if (n < 2) isPrime = false;。