1. 引言
流程控制语句让开发者能够通过决策、循环和分支,有条件地改变特定代码块的执行顺序。本文将梳理面试中常见的流程控制问题,并通过示例代码深入理解答案要点。
2. 问题详解
2.1 描述 if-then
和 if-then-else
语句。哪些表达式能作为条件?
两者都要求程序仅在条件为 true
时执行代码块。但 if-then-else
提供了备用执行路径(当 if
条件为 false
时):
if (age >= 21) {
// ...
} else {
// ...
}
⚠️ Java 只支持布尔表达式作为条件。使用其他类型会导致编译错误。
2.2 描述 switch
语句。哪些对象类型可用于 switch
子句?
switch
根据变量值选择执行路径。每个路径用 case
或 default
标记,匹配后执行后续代码直到遇到 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");
}
✅ 支持:byte
、short
、char
、int
、其包装类、enum
和 String
。
2.3 忘记在 switch
的 case
中写 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 支持哪些循环类型?
三种循环:
for
循环:适合已知迭代次数的场景for (int i = 0; i < 10; i++) { // ... }
while
循环:条件为true
时持续执行while (iterator.hasNext()) { // ... }
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; // 终止外层循环
}
}
}
结果:loopCycles
为 5(若用无标签 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; // 跳到外层循环的下一轮
}
}
}
结果:loopCycles
为 5(无标签版本为 9)。
2.10 描述 try-catch-finally
的执行流程?
try
块正常执行 → 忽略catch
,执行finally
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
中的赋值不会生效,因为 return
在 finally
执行前已将值返回。
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()
方法。资源需实现 AutoCloseable
或 Closeable
:
try (StringWriter writer = new StringWriter()) {
writer.write("Hello world!");
} // writer.close() 自动调用
3. 总结
本文梳理了 Java 流程控制的面试高频问题,涵盖分支、循环、异常处理等核心概念。这些是技术面试的起点,建议结合实际项目深入实践。祝面试顺利!