try负责试探执行,catch定向兜底,finally无条件收尾;catch需按类型从具体到宽泛排列;finally几乎总执行且可覆盖return值;优先用try-with-resources管理资源;finally中避免抛异常或return。

掌握 try-catch-finally 的核心,不在于死记语法,而在于理解三者各自的职责和协作逻辑:try 负责“试探执行”,catch 负责“定向兜底”,finally 负责“无条件收尾”。
明确每个块的不可替代作用
– try 块只能放可能抛出异常的代码;一旦抛出异常,后续语句立即跳过,控制权交给匹配的 catch 或直接进入 finally。
– catch 按异常类型从具体到宽泛排列(如先 IOException 再 Exception),否则编译报错或导致子类异常被父类提前捕获而丢失精度。
– finally 几乎总会执行(唯一例外是 JVM 直接退出,如调用 System.exit() 或发生致命错误),哪怕 try/catch 中有 return 语句——它会在 return 返回前执行。
注意 return 与 finally 的执行顺序
当 try 或 catch 中有 return,程序会先记录返回值,再执行 finally;若 finally 中也写 return,它会覆盖前面的返回值(不推荐!)。例如:
int method() {
try { return 1; }
catch (Exception e) { return 2; }
finally { return 3; }
}
该方法恒返回 3。这不是 bug,而是设计行为,务必警惕。
优先用 try-with-resources 替代手动 finally 关闭资源
对于实现了 AutoCloseable 的资源(如 FileInputStream、Connection),应优先使用 try-with-resources 语法:
try (FileInputStream fis = new FileInputStream("a.txt")) {
// 使用 fis
} // 自动调用 fis.close()
它比手写 finally 更简洁、更安全,能确保即使构造函数成功但读取时异常,资源仍会被关闭。
避免在 finally 中抛出新异常或掩盖原异常
如果 try 中已抛异常,finally 再 throw 新异常,原始异常将被丢弃(除非使用 addSuppressed)。常见反模式:
– 在 finally 里调用可能抛异常的 close(),又没做二次 try-catch。
– 在 finally 中写 return 或 throw,干扰主流程逻辑。
建议:finally 仅做清理,不改变控制流;若清理操作可能失败,应单独捕获处理,而非向外传播。










