核心原则是try块仅包裹真正可能抛异常的语句:对象创建、赋值、计算等安全操作应移出try;用final变量+防御性检查替代try内赋值;拆分方法使try聚焦单一io或解析职责;善用try-with-resources管理资源。

核心原则是:try块只包裹真正可能抛异常的语句,其他初始化、赋值、计算等“安全操作”应移出try范围。无关紧要的赋值不仅稀释热点密度、干扰JIT优化,还会让异常堆栈不清晰、日志定位困难,也违背了“异常处理与正常流程分离”的设计意图。
把确定不会抛异常的代码全挪到 try 外面
比如对象创建、字段赋值、字符串拼接、数值计算、集合初始化等——只要不涉及IO、反射、解析、外部调用,基本都属于“安全操作”。这些代码放在 try 内,既无必要,又增加异常表复杂度。
- ❌ 错误写法:所有变量都在 try 里声明+赋值
try {
String orderId = request.getOrderId();
int retryCount = config.getMaxRetry() + 1;
List
File file = new File(uploadPath, orderId + ".tmp");
Files.write(file.toPath(), data); // 这行才可能抛 IOException
}
- ✅ 正确写法:仅保留真正风险操作
String orderId = request.getOrderId();
int retryCount = config.getMaxRetry() + 1;
List
File file = new File(uploadPath, orderId + ".tmp");
try {
Files.write(file.toPath(), data);
}
用 final 变量提前声明,配合防御性检查替代部分赋值
很多所谓“赋值”,本质是为后续校验做准备。与其在 try 里赋值再判断,不如用 final 声明 + 明确校验逻辑,从源头规避异常。
- 用 Objects.requireNonNull() 替代 null 判断后赋值
- 用 StringUtils.isBlank() 预检字符串,而不是等 parseLong() 抛 NumberFormatException
- 用 CollectionUtils.isNotEmpty() 检查集合,而非依赖 get(0) 触发 IndexOutOfBoundsException
拆分方法,让 try 块聚焦单一职责
一个 try 块如果包含 10 行代码,其中 7 行是准备数据,只有 3 行是实际 IO 或解析,就该拆。把准备逻辑抽成 private 方法,返回干净参数;try 块只负责调用和捕获。
- prepareRequestParams() → 不含 try,纯构造与校验
- callThirdPartyApi(params) → 仅含 HTTP 调用,用 try 包裹
- 这样 JIT 更容易将 prepareRequestParams() 内联,callThirdPartyApi() 的异常路径也更清晰
善用 try-with-resources 和构造时初始化
资源类(如 InputStream、Connection)的创建本身通常不抛异常,但 close() 会。用 try-with-resources 可自动管理,无需手动赋值+finally 关闭;同时把资源获取逻辑尽量前置:
- ✅ Path path = Paths.get(uri); // 安全
- ✅ try (InputStream is = Files.newInputStream(path)) { ... } // 异常只来自 open 操作
- ❌ 不要在 try 内反复 new String()、new HashMap()、拼接 JSON 字符串
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











