java异常处理应依“谁有能力处理”选择try-catch或throws;优先捕获具体异常类型,避免宽泛捕获;受检异常慎用,推荐统一非受检异常加全局处理器;禁止吞异常、空catch、printstacktrace。

Java里异常处理没有放之四海而皆准的“最佳实践”,只有贴合场景的合理选择:该捕获的捕获,该抛出的抛出,不该吞掉的绝不能静默吃掉。
什么时候该用 try-catch,什么时候该 throws?
核心判断依据是「谁有能力处理这个异常」。如果当前方法知道怎么恢复、重试、降级或给出明确反馈,就用 try-catch;如果只是中间层,既不理解异常含义,也无法干预流程,就老老实实 throws 给上层。
-
IOException在文件读取方法里通常该throws,但在用户上传头像的 Service 方法里,可能需要捕获并转为BusinessException返回友好提示 - 数据库操作中遇到
SQLException,DAO 层一般不自己catch,而是由 Spring 的@Transactional或统一异常处理器接管 - 不要在工具类方法(如
StringUtils.parseLong())里try-catch NumberFormatException后返回null——这会让调用方失去错误上下文,应让异常自然抛出或封装为非受检异常
为什么不要用 catch (Exception e) 或 catch (Throwable t)?
这类宽泛捕获会掩盖真正的问题,比如把 OutOfMemoryError 或 StackOverflowError 也一并吞掉,导致系统带病运行、问题延迟暴露。
- 必须捕获时,优先捕获具体异常类型,例如
catch (FileNotFoundException e)或catch (SQLTimeoutException e) - 若真需兜底,应在最外层(如 Spring 的
@ControllerAdvice)用catch (RuntimeException e),且务必记录完整堆栈,不能只打e.getMessage() -
catch (Error e)几乎总是错的——Error表示 JVM 级严重问题,程序不应尝试恢复
受检异常(Checked Exception)到底还要不要用?
Java 的受检异常设计本意是强制开发者考虑失败路径,但实际中常被滥用:要么层层 throws 导致签名臃肿,要么用 catch + throw new RuntimeException(e) 粗暴转化,丢失语义。
立即学习“Java免费学习笔记(深入)”;
- 对外提供的 SDK 或框架 API 可谨慎使用受检异常(如
javax.crypto.BadPaddingException),因为它确实代表调用方可能犯的可预期错误 - 内部服务间调用、Web 接口层、Spring Boot 项目中,更推荐统一用非受检异常(
RuntimeException子类),配合全局异常处理器返回标准 JSON 错误体 - 若保留受检异常,不要在
catch块里空着(catch (Exception e) {}),也不要用e.printStackTrace()——日志必须包含上下文信息,例如「查询用户 ID=12345 时 DB 连接超时」
异常不是日志的替代品,也不是控制流的拐杖。一个被频繁抛出又立即捕获的异常,往往说明设计出了问题——与其反复 try-catch,不如提前校验、优化接口契约,或者换用 Optional、Result 等更明确的返回类型。










