java异常处理核心是让错误可识别、可追溯、可恢复;优先用try-with-resources自动关闭资源,避免finally中return或throw,按类型捕获并记录日志,受检异常应合理声明或处理。

Java异常处理的关键不在“兜住错误”,而在于让错误可识别、可追溯、可恢复。资源关闭只是其中一环,但恰恰是最容易出错、影响最直接的部分——关不掉的文件流、连不上的数据库、没释放的Socket,轻则内存泄漏,重则服务雪崩。
优先用 try-with-resources,别手写 finally 关闭
传统 try-finally 关闭资源要写多层嵌套,稍有疏忽就漏关或覆盖异常。try-with-resources 是编译期语法糖,只要资源实现 AutoCloseable(JDK 大部分 I/O、JDBC、网络类都已实现),就能自动调用 close(),且支持异常抑制机制——即使 close() 抛异常,原始异常仍会保留为主异常。
- Java 7+ 写法:直接在 try 后括号中声明新资源,如
try (FileInputStream fis = new FileInputStream("a.txt")) - Java 9+ 升级写法:可复用已有变量,
FileInputStream fis = ...; try (fis) { ... },更灵活、更少重复 - 多个资源用分号隔开:
try (Connection conn = ds.getConnection(); PreparedStatement ps = conn.prepareStatement(sql))
别在 finally 里 return 或 throw
finally 块本意是执行清理,不是控制流程出口。一旦 finally 中有 return 或抛异常,它会直接终结方法,导致 try 或 catch 中的 return 被丢弃、原始异常被掩盖。
- 例如:try 中 return "ok",finally 中 return "fail" → 实际返回 "fail",且调用方完全不知道前面发生了什么
- 再如:try 中抛出 IOException,finally 中 close() 又抛出 SQLException → 最终只看到 SQLException,原始 IO 问题彻底丢失
- 正确做法:finally 只做清理;需要返回值或抛异常,统一放在 try/catch 末尾处理
按类型捕获,不吞异常,也不泛捕 Exception
捕获异常不是为了“让它消失”,而是为了做有意义的事:记录、补偿、降级、重试或向上透传。泛捕 Exception 或空 catch 是最危险的习惯之一。
- 避免
catch (Exception e) { }—— 这等于给 bug 盖了层马甲 - 按实际场景分层捕获:比如先 catch SQLException 处理数据库特有问题,再 catch IOException 应对网络波动,最后用一个通用 catch 包底(如有必要)
- 捕获后至少记录日志(含完整堆栈),或重新包装为业务异常并带上上下文,如
throw new OrderProcessException("支付回调验签失败", e)
检查型异常该声明就声明,别硬吞也别乱转 RuntimeException
IOException、SQLException 这类受检异常,是编译器在提醒你:“这个操作天然不可靠,请正视它”。强行用 RuntimeException 包一层,看似省事,实则把责任推给了调用方,破坏了契约清晰性。
- 如果当前层能合理处理(如重试、默认值、降级响应),就 catch 并消化
- 如果处理不了,就在方法签名中用 throws 明确声明,让上层决定策略
- 自定义异常优先继承 Exception(需检查)或 RuntimeException(逻辑错误),名称要见名知义,如 PaymentTimeoutException、InventoryLockFailedException
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











