应避免直接捕获Exception,需缩小捕获范围、分类处理异常、保留原始堆栈、禁止静默吞异常;只捕获明确可处理的类型,如IOException、SQLException等,其他让其向上抛出。

直接捕获 Exception(尤其是顶级异常)会让真正出问题的地方被掩盖,日志看不出堆栈根源,调试困难,还可能掩盖本该抛出的运行时异常。重构核心是:**缩小捕获范围、分类处理、保留原始上下文、避免静默吞异常**。
只捕获明确需要处理的异常类型
不要用 catch (Exception e) 一把抓。明确业务中可能出现且你有能力恢复的异常,比如 IOException、SQLException、特定业务异常(如 InsufficientBalanceException),其他异常应让其向上抛出,由更高层统一处理或记录。
- ✅ 正确示例:
catch (IOException e) { log.warn("文件读取失败,使用默认配置", e); return getDefaultConfig(); } - ❌ 错误示例:
catch (Exception e) { log.info("出错了"); }—— 没有日志堆栈,没做任何补偿,连是什么错都不知道
用多 catch 或 try-with-resources 避免泛型捕获
Java 7+ 支持多异常捕获,可对不同异常做差异化处理;涉及资源操作时优先用 try-with-resources,它自动关闭资源并把底层异常正确传播,减少手动 finally 和异常掩盖风险。
- 多 catch 示例:
catch (SQLException e) { rollback(); throw new ServiceException("DB error", e); } catch (IllegalArgumentException e) { throw e; // 不包装,保持语义清晰 } - try-with-resources 示例:
try (FileInputStream fis = new FileInputStream(file)) { ... }—— 即使读取时抛异常,流也会自动关闭,不会因关闭失败覆盖主异常
必要时包装异常但保留 cause
如果必须转换异常类型(比如将底层技术异常转为业务异常),务必用带 cause 的构造函数,确保原始堆栈不丢失。不要只写 new BusinessException("操作失败"),而要写 new BusinessException("操作失败", e)。
本文档主要讲述的是Eclipse导入Android或其他的JAVA项目的正确方法;希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看
立即学习“Java免费学习笔记(深入)”;
- ✅ 保留根因:
throw new PaymentFailedException("支付调用超时", e); - ❌ 破坏链路:
throw new PaymentFailedException("支付调用超时");—— 原始超时是SocketTimeoutException?还是NullPointerException?无从得知
绝不在 catch 块里空着或只打 info 日志
空 catch 是最危险的重构点。哪怕暂时没想好怎么处理,至少要记录 ERROR 级别日志并带上完整堆栈;如果确定可忽略(极少数场景,如关闭已关闭的流),也要加明确注释说明原因。
- 最低要求:
catch (InterruptedException e) { Thread.currentThread().interrupt(); log.error("线程被中断", e); } - 禁止写法:
catch (Exception e) {}或catch (Exception e) { log.info("忽略异常"); }
重构不是追求“不报错”,而是让错误暴露得及时、清晰、可追溯。缩小捕获范围 + 分类响应 + 保留 cause + 日志到位,四者缺一不可。








