异常处理核心是“先捕获、再包装、后抛出”,需精准捕获具体异常类型,用自定义异常包装并传入cause,于抽象边界处转换,避免信息丢失或语义混乱。

捕获并转换底层异常,核心是“先捕获、再包装、后抛出”,目的是把技术细节(如数据库连接失败)转成业务语义(如用户登录失败),同时保留原始错误线索。
明确捕获具体异常类型
不要用 catch (Exception e) 一锅端,而是精准捕获底层异常,比如 SQLException 或 IOException。这样能避免误吞其他无关异常,也便于后续做针对性转换。
- 受检异常必须显式处理,不捕获或不声明 throws 就编译不过
- 运行时异常(如 NullPointerException)虽可不捕获,但若属于可预期的业务边界(如参数校验失败),建议主动捕获并转为业务异常
- 多个底层异常共存时,可用 Java 7+ 的多异常语法:catch (SQLException | IOException e)
用自定义异常包装并传入 cause
新建业务异常类,继承 Exception(需强制处理)或 RuntimeException(更常用,避免层层 throws)。构造时务必调用父类含 Throwable cause 的构造器,把原始异常作为 cause 传入。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 例如:throw new UserLoginFailedException("用户名或密码错误", e);
- 这样能保证原始堆栈完整保留在 e.getCause() 中,日志和调试时可逐层展开
- 可在构造中补充业务上下文,比如当前操作的用户 ID、请求 ID,方便问题定位
转换时机选在抽象边界处
异常转换不是处处都做,而应在层与层之间交接的关键点进行,比如 DAO 层 → Service 层、远程调用入口、API 控制器。
立即学习“Java免费学习笔记(深入)”;
- DAO 层只管数据操作,抛出 SQLException 是合理的;Service 层不应暴露 SQL 细节,应转为 UserNotFoundException
- 对外提供的 API 接口,统一用一个顶层业务异常(如 BusinessException)兜底,避免把内部异常直接返回给前端
- 不要在工具类或通用方法里随意转换,容易导致语义混乱或重复包装
避免常见陷阱
转换过程容易忽略细节,导致信息丢失或行为异常。
- 别只记录日志就丢弃原始异常——没 re-throw 就等于“吃掉”异常,流程会静默中断
- 不要在 finally 块里 return 或抛异常,它会覆盖 try/catch 中的返回值或异常
- 禁止 catch (Throwable t) 后简单 log.info(t),这会吞掉 OutOfMemoryError 等致命错误
- 转换后的异常消息应面向开发者或运维,而非终端用户;对用户提示需另外做国际化或脱敏处理

















