Java中try必须配catch或finally;受检异常须处理,运行时异常建议处理;catch顺序须从具体到宽泛;try内变量作用域受限;finally中return会覆盖try/catch返回值。

try catch 基本写法和必须遵守的语法规则
Java 中 try 块必须至少跟一个 catch 或 finally,不能单独存在。编译器会强制检查受检异常(checked exception),比如 IOException、SQLException,不捕获或声明就报错;而运行时异常(unchecked),如 NullPointerException、ArrayIndexOutOfBoundsException,可以不写 catch 但建议处理。
-
catch子句的参数类型必须是Throwable的子类,且多个catch顺序必须从具体到宽泛,否则编译失败(例如先写Exception再写IOException会报错) -
try块中声明的变量作用域仅限于该块内,不能在catch或finally中直接访问 - 如果
try中有return,且finally也有return,最终返回的是finally的值(这点极易被忽略)
如何正确捕获并处理 IOException 这类受检异常
读文件是最典型场景,FileInputStream 构造或 read() 方法都抛出 IOException,必须显式处理。不推荐空 catch,也不建议只打日志却不做恢复或提示。
try (FileInputStream fis = new FileInputStream("data.txt")) {
int b;
while ((b = fis.read()) != -1) {
System.out.write(b);
}
} catch (FileNotFoundException e) {
System.err.println("文件未找到: " + e.getMessage());
} catch (IOException e) {
System.err.println("读取异常: " + e.getMessage());
}- 优先用带资源声明的
try-with-resources(上例),自动关闭流,避免因忘记close()导致资源泄漏 - 分开捕获
FileNotFoundException和更通用的IOException,能更精准响应不同错误原因 - 不要把异常信息直接暴露给终端用户,尤其生产环境;应记录完整堆栈(
e.printStackTrace()仅适合调试)
finally 里写 return 会覆盖 try/catch 的返回值
这是 Java 异常机制里最反直觉的行为之一:只要 finally 有 return,它就会“劫持”整个方法的返回结果,无论 try 或 catch 返回什么。
public static String getValue() {
try {
return "from try";
} catch (Exception e) {
return "from catch";
} finally {
return "from finally"; // 实际返回这个
}
}- 上述方法永远返回
"from finally",即使try正常执行 - 如果
finally抛出新异常,它会完全掩盖try或catch中已发生的异常 - 除非明确需要拦截返回值(极少见),否则
finally中禁止return或抛异常
何时该 throw 新异常而不是吞掉原异常
在封装底层 API 时,比如 DAO 层调用 JDBC,不应把 SQLException 直接暴露给 service 层。要用 throw new RuntimeException("业务操作失败", e) 包装,并保留原始异常(即传入 e 作为 cause),否则丢失关键上下文。
立即学习“Java免费学习笔记(深入)”;
- 使用
throw new XXXException(message, cause)构造函数,确保异常链完整 - 不要用
catch (Exception e) { /* 忽略 */ }吞掉异常——这会让问题彻底消失,线上难排查 - 自定义异常类应继承
RuntimeException(非受检)或Exception(受检),取决于是否强制调用方处理
异常不是流程控制手段,过度依赖 try catch 替代条件判断(比如用 NumberFormatException 判断字符串是否为数字)会影响可读性和性能。真正该捕获的,是那些你有能力响应、恢复或记录的意外状况。










