
Java 中 try-catch 不是用来“兜底所有错误”的,它只捕获运行时抛出的 Throwable 子类(即 Exception 和 Error 的子类),而编译期错误、逻辑 bug、空指针未触发异常时都不会进入 catch 块。
什么时候必须写 catch 或声明 throws
Java 强制要求处理 checked exception(受检异常),比如 IOException、SQLException。不处理会编译失败。
- 要么用
try-catch捕获并处理 - 要么在方法签名加
throws IOException向上抛出 -
RuntimeException及其子类(如NullPointerException、ArrayIndexOutOfBoundsException)属于unchecked exception,编译器不强制处理
多个 catch 的顺序为什么不能乱
Java 从上到下匹配 catch,一旦某个 catch 的类型能接收当前异常,就不再往下看。如果把父类写在前面,子类 catch 永远不会执行。
try {
throw new FileNotFoundException();
} catch (IOException e) { // ✅ 能捕获,但太宽泛
System.out.println("IO error");
} catch (FileNotFoundException e) { // ❌ 编译报错:unreachable code
System.out.println("File not found");
}
- 必须先写子类异常,再写父类,例如:
FileNotFoundException→IOException→Exception - 使用多异常捕获语法(Java 7+)可合并同类处理:
catch (IOException | SQLException e)
finally 一定会执行吗
绝大多数情况下会执行,但有三个典型例外:
立即学习“Java免费学习笔记(深入)”;
- JVM 退出:在
try或catch中调用了System.exit(0) - 线程被强制中断(如
Thread.stop(),已废弃但仍有影响) -
finally前发生了致命错误(如OutOfMemoryError),JVM 可能来不及执行
另外注意:return 在 try 中出现时,finally 仍会执行——但若 finally 里也有 return,则会覆盖 try 中的返回值。
try-with-resources 是更安全的替代方案
对实现了 AutoCloseable 的资源(如 FileInputStream、Connection),优先用 try-with-resources,它自动调用 close(),且比手动写 finally 更可靠。
try (FileInputStream fis = new FileInputStream("a.txt")) {
// 使用 fis
} catch (IOException e) {
// 处理异常
} // fis.close() 在这里自动执行,即使发生异常
- 资源声明必须在
try后括号内,且对象必须是final或等效不可变 - 如果
close()本身抛异常,会被抑制(suppressed),可通过e.getSuppressed()获取 - 不要在
try-with-resources外再手动调用close(),可能引发IllegalStateException
真正容易被忽略的是异常链的完整性:捕获后简单打印 e.printStackTrace() 会丢失上下文;吞掉异常(空 catch)会让问题难以定位;而过度包装(层层 new RuntimeException(e))又可能掩盖原始类型。要不要记录日志、是否重试、要不要转成业务异常,得看具体场景,不是语法能决定的。










