1. 引言

流程控制语句让开发者能够通过决策、循环和分支,有条件地改变特定代码块的执行顺序。本文将梳理面试中常见的流程控制问题,并通过示例代码深入理解答案要点。

2. 问题详解

2.1 描述 if-thenif-then-else 语句。哪些表达式能作为条件?

两者都要求程序仅在条件为 true 时执行代码块。但 if-then-else 提供了备用执行路径(当 if 条件为 false 时):

if (age >= 21) {
    // ...
} else {
    // ...
}

⚠️ Java 只支持布尔表达式作为条件。使用其他类型会导致编译错误。

2.2 描述 switch 语句。哪些对象类型可用于 switch 子句?

switch 根据变量值选择执行路径。每个路径用 casedefault 标记,匹配后执行后续代码直到遇到 break;无匹配时执行 default 块:

switch (yearsOfJavaExperience) {
    case 0:
        System.out.println("Student");
        break;
    case 1:
        System.out.println("Junior");
        break;
    case 2:
        System.out.println("Middle");
        break;
    default:
        System.out.println("Senior");
}

✅ 支持:byteshortcharint、其包装类、enumString

2.3 忘记在 switchcase 中写 break 会发生什么?

会导致穿透(fall-through):即使后续 case 不匹配,也会继续执行直到遇到 break。示例:

int operation = 2;
int number = 10;

switch (operation) {
    case 1:
        number = number + 10;
        break;
    case 2:
        number = number - 4;
    case 3:
        number = number / 3;
    case 4:
        number = number * 10;
        break;
}

执行后 number 值为 20(而非预期 6)。这可用于多个 case 共享同一逻辑。

2.4 何时优先用 switch 而非 if-else,反之亦然?

switch 的场景

  • 单个变量匹配多个离散值
  • 多个值执行相同代码
    switch (month) {
      case 1:
      case 3:
      case 5:
      case 7:
      case 8:
      case 10:
      case 12:
          days = 31;
          break;
      case 2:
          days = 28;
          break;
      default:
          days = 30;
    }
    

if-else 的场景

  • 检查值范围
  • 多条件组合判断
    if (aPassword == null || aPassword.isEmpty()) {
      // 空密码
    } else if (aPassword.length() < 8 || aPassword.equals("12345678")) {
      // 弱密码
    } else {
      // 强密码
    }
    

2.5 Java 支持哪些循环类型?

三种循环:

  1. for 循环:适合已知迭代次数的场景
    for (int i = 0; i < 10; i++) {
         // ...
    }
    
  2. while 循环:条件为 true 时持续执行
    while (iterator.hasNext()) {
         // ...
    }
    
  3. do-while 循环:至少执行一次,条件在循环末尾判断
    do {
         // ...
    } while (choice != -1);
    

2.6 什么是增强型 for 循环?

for 循环的简化语法,用于遍历集合、数组、枚举或实现 Iterable 接口的对象:

for (String aString : arrayOfStrings) {
    // ...
}

2.7 如何提前退出循环?

使用 break 立即终止循环:

for (int i = 0; ; i++) {
    if (i > 10) {
        break;
    }
}

2.8 无标签 break 和带标签 break 的区别?

  • **无标签 break**:终止最内层 switch/for/while/do-while
  • **带标签 break**:终止指定标签的外层语句

示例:

int[][] table = { { 1, 2, 3 }, { 25, 37, 49 }, { 55, 68, 93 } };
boolean found = false;
int loopCycles = 0;

outer: for (int[] rows : table) {
    for (int row : rows) {
        loopCycles++;
        if (row == 37) {
            found = true;
            break outer; // 终止外层循环
        }
    }
}

结果:loopCycles5(若用无标签 break 则为 8)。

2.9 无标签 continue 和带标签 continue 的区别?

  • **无标签 continue**:跳过最内层循环的当前迭代
  • **带标签 continue**:跳转到指定标签的外层循环

示例:

int[][] table = { { 1, 15, 3 }, { 25, 15, 49 }, { 15, 68, 93 } };
int loopCycles = 0;

outer: for (int[] rows : table) {
    for (int row : rows) {
        loopCycles++;
        if (row == 15) {
            continue outer; // 跳到外层循环的下一轮
        }
    }
}

结果:loopCycles5(无标签版本为 9)。

2.10 描述 try-catch-finally 的执行流程?

  1. try 块正常执行 → 忽略 catch,执行 finally
  2. try 块抛出异常:
    • 匹配的 catch 块处理异常 → 执行 finally
    • 无匹配 catch → 异常抛给调用栈上层 → 执行 finally

finally 始终执行(除非 JVM 终止或线程被杀死)。

2.11 哪些情况 finally 块不会执行?

  • 调用 System.exit()
  • 执行线程被中断或杀死
  • JVM 崩溃

2.12 执行以下代码的结果是什么?

public static int assignment() {
    int number = 1;
    try {
        number = 3;
        if (true) {
            throw new Exception("Test Exception");
        }
        number = 2;
    } catch (Exception ex) {
        return number; // 返回 3
    } finally {
        number = 4; // 已不影响返回值
    }
    return number;
}

System.out.println(assignment()); // 输出 3

finally 中的赋值不会生效,因为 returnfinally 执行前已将值返回。

2.13 即使不抛异常,何时仍需用 try-finally

场景 1:确保资源清理,避免因 break/continue/return 跳过

HeavyProcess heavyProcess = new HeavyProcess();
try {
    // ...
    return heavyProcess.heavyTask();
} finally {
    heavyProcess.doCleanUp(); // 必执行
}

场景 2:无法本地处理异常,但仍需释放资源

public void doDangerousTask(Task task) throws ComplicatedException {
    try {
        // ...
        task.gatherResources();
        if (task.isComplicated()) {
            throw new ComplicatedException("Too difficult");
        }
        // ...
    } finally {
        task.freeResources(); // 必执行
    }
}

2.14 try-with-resources 如何工作?

自动管理资源:声明资源后,无论是否发生异常,都会在语句结束时调用其 close() 方法。资源需实现 AutoCloseableCloseable

try (StringWriter writer = new StringWriter()) {
    writer.write("Hello world!");
} // writer.close() 自动调用

3. 总结

本文梳理了 Java 流程控制的面试高频问题,涵盖分支、循环、异常处理等核心概念。这些是技术面试的起点,建议结合实际项目深入实践。祝面试顺利!


原始标题:Java Flow Control Interview Questions (+ Answers)