try-catch-finally 用于有序应对异常、保障关键逻辑执行和防止资源泄漏;应捕获具体异常、按子类在前父类在后排列;finally 必须执行收尾动作但避免抛异常;优先使用 try-with-resources 管理 AutoCloseable 资源;不用异常替代逻辑判断,禁止空 catch。

try-catch-finally 是 Java(及其他类似语言)中结构化异常处理的核心机制,它的作用不是“避免异常”,而是**有秩序地应对异常、保障关键逻辑执行、防止资源泄漏**。用对了,代码更健壮;用错了,可能掩盖问题或引发新错误。
catch 要捕获具体异常,别只写 Exception
捕获过于宽泛的异常(如 catch(Exception e))会让真正需要关注的问题被忽略,也难以做针对性恢复。
- 优先捕获明确的子类异常,比如 FileNotFoundException、NumberFormatException
- 多个 catch 块按“子类在前、父类在后”排列,否则子类永远无法被捕获
- 如果真需要兜底,把 catch(Exception e) 放在最后,并记录日志或做通用清理
finally 是放“必须执行”逻辑的地方,不是“异常后才执行”
finally 块无论是否发生异常、是否被 catch、甚至在 try/catch 中 return 了,都会执行。这是它最常被误用的点。
- 适合关闭文件流、释放数据库连接、解锁同步锁等“收尾动作”
- 避免在 finally 中写可能抛异常的逻辑(除非你再次 try-catch),否则会覆盖原异常
- 注意:如果 try 或 catch 中执行了 System.exit(),finally 不会执行
try-with-resources 更简洁安全(Java 7+)
对于实现了 AutoCloseable 的资源(如 FileInputStream、Connection),推荐用 try-with-resources 替代手动 finally 关闭。
- 资源在 try 括号内声明,自动调用 close(),无需显式 finally
- 即使 try 块中抛出异常,close() 仍会被调用;若 close() 本身也抛异常,会被抑制(可通过 getSuppressed() 获取)
- 示例:try (FileInputStream fis = new FileInputStream("a.txt")) { ... }
不要用 try-catch 替代逻辑判断
异常机制成本较高,且语义上表示“意外情况”。用它来控制正常流程(比如用 NumberFormatException 判断字符串是否为数字),既低效又难维护。
- 该用 if 判断的就用 if,比如用 String.matches("\d+") 或 Character.isDigit() 预检
- 异常应留给真正不可预期的情况,如网络超时、磁盘满、权限不足等
- 过度捕获和吞掉异常(空 catch 块)等于埋雷,至少要 log.warn 或 log.error

















