最直接的办法是:绝不允许空catch块,必须用logger.error("描述性消息", e)记录完整堆栈;只捕获具体异常类型如ioexception、sqlexception;包装异常时须传入原异常作为cause;资源清理优先用try-with-resources,finally中不抛新异常。

最直接的办法是:绝不允许空 catch 块,必须记录完整堆栈,并明确异常处理意图。
禁止空 catch 或仅打印简单提示
catch 块里只写 e.printStackTrace() 或 System.out.println("error"),等于丢掉关键线索。这类写法不进日志系统、无上下文、无堆栈,线上出问题时完全无法回溯。
- 必须用日志框架的 logger.error("描述性消息", e),确保堆栈完整输出
- 若真要忽略某个已知异常(如 InterruptedException),需显式注释说明原因,并调用 Thread.currentThread().interrupt() 恢复中断状态
- 绝对避免 e.printStackTrace() —— 它输出到 System.err,不受日志配置管控,容易遗漏或混杂
只捕获具体异常类型,不泛化抓 Exception
用 catch (Exception e) 会把 NullPointerException、OutOfMemoryError 全部吞下,掩盖本该暴露的编码缺陷或严重故障。
- 只捕获你明确知道如何响应的异常,例如 IOException、SQLException、TimeoutException
- 不要捕获 Throwable 或 Error 子类;它们代表系统级崩溃,不应由业务代码处理
- 统一兜底逻辑应放在顶层(如 Spring 的 @ControllerAdvice),而非每层都写泛化 catch
包装异常时务必保留原始 cause
用 new RuntimeException("xxx") 替换原异常,却不传入 e 作为 cause,会导致调用链断裂,日志里只看到最后一层抛出点,找不到真正出错位置。
- 所有自定义异常包装都必须使用带 cause 的构造函数:throw new ServiceException("DB 查询失败", e)
- 日志中也要用 logger.error(msg, e),而不是 logger.error(msg + e) —— 后者只打 toString(),丢失堆栈
- 检查所用框架是否自动保留 cause(如 Spring 的 DataAccessException),别默认它做了
finally 中不抛新异常,资源清理优先用 try-with-resources
如果 try 已抛异常,finally 再抛一个,JVM 会丢弃原始异常,只留下 finally 的那个——排查时完全被误导。
- finally 块中禁止抛受检异常;对 close() 等可能失败的操作,应内部捕获并记录,但不向上抛
- 资源清理首选 try-with-resources:只要实现 AutoCloseable(JDK 7+ 大部分 IO 类已支持),就能保证异常发生时仍执行 close()
- 避免在 try-with-resources 的资源声明中调用可能抛异常的方法(如 new Socket(host, port)),否则资源初始化失败会导致后续 close() 不执行
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











