优先用单层、职责分明的异常处理而非嵌套;外层管业务流程恢复,内层管子动作兜底,每层只捕获自身能处理的异常,避免空catch、catch Exception或Throwable,善用try-with-resources分离资源与业务逻辑。

嵌套 try-catch 不是“能不能写”,而是“要不要写”——多数情况下,**优先用单层、职责分明的异常处理,而非层层嵌套**。真需要嵌套时,核心是:**外层管业务逻辑恢复,内层管具体操作兜底,且每层只捕获自己能处理的异常**。
明确每一层 try 的责任边界
外层 try 应聚焦“整体流程是否还能继续”,比如下单主流程;内层 try 则专注“某个子动作失败能否局部修复”,比如发短信失败后改发站内信。
- 外层不捕获 NullPointerException、IllegalArgumentException 这类编程错误,留给上层或全局异常处理器
- 内层只 catch 自己调用的代码可能抛出的受检异常(如 IOException)或明确可重试的运行时异常(如 SQLException)
- 避免“一个 try 包整个方法”,把网络请求、文件读取、数据库更新分别用独立 try 包裹
用具体异常类型代替 Exception 或 Throwable
写 catch (Exception e) 是嵌套混乱的起点——它掩盖了意图,也容易误吞本该向上冒泡的异常。
- 内层捕获
SocketTimeoutException尝试重试,而UnknownHostException直接抛出 - 外层捕获
OrderProcessingException(自定义业务异常),记录日志并返回用户友好提示 - 绝不出现
catch (Throwable t)——这是反模式,会吞掉 OutOfMemoryError 等致命问题
避免“空 catch”和“只打印堆栈”
嵌套中每一处 catch 都必须有明确动作:恢复、转换、记录、告警或重新抛出。
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
立即学习“Java免费学习笔记(深入)”;
- 内层 catch 后若无法恢复,应封装为更上层语义的异常再 throw,例如:
throw new PaymentFailureException("微信支付调用超时", e); - 外层 catch 到业务异常后,做补偿操作(如解锁库存)、通知运营、返回错误码,而不是只写
e.printStackTrace() - 日志记录用
log.error("下单失败,订单号: {}", orderId, e),保留原始异常链,方便追踪根因
考虑用 try-with-resources + 单层结构替代部分嵌套
很多所谓“嵌套”,其实是资源管理与业务逻辑混在一起。用 try-with-resources 把资源生命周期收口,业务异常单独处理,结构立刻清爽。
比如读配置文件并解析 JSON:
try (InputStream is = Files.newInputStream(configPath)) {
String json = IOUtils.toString(is, StandardCharsets.UTF_8);
return objectMapper.readValue(json, Config.class);
} catch (IOException e) {
throw new ConfigLoadException("配置文件读取失败", e);
} catch (JsonProcessingException e) {
throw new ConfigLoadException("配置格式错误", e);
}
这里没有嵌套 try,但清晰分离了资源关闭(自动)、IO 异常、JSON 解析异常三类问题。

















