生产环境禁止e.printStackTrace(),须用SLF4J记录带业务标识的日志;禁用空catch;受检异常仅用于调用方必须恢复的场景;finally中避免抛异常,优先用try-with-resources;异常信息需含可行动上下文并脱敏敏感数据。
避免在 catch 块里只写 e.printStackTrace()
这是最常见也最危险的习惯——它把异常信息输出到标准错误流,既没记录上下文,也没触发监控,线上出问题时根本没法定位。生产环境必须用日志框架(如 SLF4J)记录,并带上关键业务标识。
- 用
logger.error("订单支付失败,orderNo={}", orderNo, e),而非e.printStackTrace() - 不要吞掉异常:空
catch块或只打日志不抛出/不处理,等于掩盖故障 - 若决定忽略某类异常(如
InterruptedException在清理线程时),必须加明确注释说明“为什么可忽略”
区分 RuntimeException 和受检异常的使用场景
Java 强制你处理受检异常(Exception 及其子类,但不包括 RuntimeException),但这不意味着“所有异常都该是受检的”。滥用受检异常会导致大量无意义的 throws 声明和模板式 try-catch,反而降低可读性。
- 受检异常适合:调用方**必须决策如何恢复**的场景,比如
IOException(文件不存在?重试?降级?) -
RuntimeException更适合:程序逻辑错误或不可恢复的意外,如IllegalArgumentException、NullPointerException(应提前校验,而非靠 catch) - 自定义异常优先继承
RuntimeException,除非你有强契约要求调用方显式处理
不要在 finally 里执行可能抛异常的操作
finally 的本意是保证资源释放,但如果里面又抛出新异常,会覆盖原始异常,导致根因丢失——这是调试时最让人抓狂的问题之一。