Java编码规范:try-catch块编写的统一风格指南

作者:袖梨 2026-06-23
Java异常处理应精准而非冗余:try块仅含易失败操作,catch需具体、带上下文日志并明确动作,finally仅限资源释放,分层收口由统一处理器响应。

Java中try-catch不是写得越多越安全,而是写得越准、越少、越有迹可循才越可靠。统一风格的核心目标不是统一格式,而是统一责任——让异常在哪发生、被谁处理、如何记录、是否传播,一目了然。

try块只放“真可能出错”的代码

一个try里塞进参数校验、日志打印、DTO转换、业务判断,等于把异常信号埋进噪音里。真正该放进try的,只有那些JVM或底层API明确会抛受检异常、或实际运行中易失败的操作:

  • 文件读写(FileInputStreamFiles.readAllLines
  • 数据库操作(JdbcTemplate.queryConnection.createStatement
  • 远程调用(RestTemplate.getForObjectFeignClient接口调用
  • JSON序列化/反序列化(ObjectMapper.readValue
  • 数值或时间格式解析(Integer.parseIntLocalDateTime.parse

其他逻辑——比如if (obj == null) throw new IllegalArgumentException()、Objects.requireNonNull()、日志打点——全部移出try。这既缩小了异常监控范围,也避免掩盖真实问题边界。

catch必须具体、带日志、有动作

禁止出现catch (Exception e) { }或e.printStackTrace()这类“假处理”。每个catch块至少完成三件事:

立即学习“Java免费学习笔记(深入)”;

  • 按继承顺序精准捕获:FileNotFoundException → IOException → Exception;子类在前,否则编译不通过且逻辑失效
  • 日志必须带原始异常和业务上下文:用log.error("订单[{}]支付回调解析失败", orderId, e),而非log.error("解析失败")
  • 明确后续动作:返回降级值需注释说明原因;重抛必须包装(throw new ServiceException("支付回调异常", e));静默兜底仅限极少数已评审场景

finally只做资源释放,不用它写业务逻辑

finally的唯一正当用途是释放资源——关流、断连、解锁。现代Java优先使用try-with-resources替代手动finally,语义更清晰、关闭更可靠:

  • 所有实现AutoCloseable的资源(InputStreamConnectionScanner等)都应声明在try括号内
  • 若必须用finally,禁止在里面写日志、调用服务、修改状态、return或throw
  • 特别警惕finally里return会覆盖try/catch的返回值,这是隐蔽的逻辑陷阱

分层收口,非必要不分散写try-catch

Service层一般不主动捕获并吞异常,而是让受检异常向上抛(如throws IOException),由统一异常处理器集中响应:

  • @RestControllerAdvice处理Controller层异常:业务异常转友好提示,系统异常记全栈,受检异常映射HTTP状态码
  • Service方法签名显式声明受检异常,避免用catch (Exception e)一锅端,掩盖底层真实问题
  • 工具类或底层封装(如JSON工具、文件工具)可提供带日志+重抛的标准模板,但不替代上层决策

相关文章

精彩推荐