java接口不应声明受检异常,因其破坏契约稳定性、绑架调用方且违背开闭原则;应改用运行时异常承载业务错误语义,通过统一异常类、全局处理器、文档与sdk保障兼容性与解耦。

Java接口不该声明受检异常——这不是灵活性不够,而是设计目标错位。真正要解决的不是“怎么让接口兼容受检异常”,而是如何让错误语义清晰、稳定、可演进,同时不绑架调用方的编码习惯和编译约束。
接口声明受检异常会破坏三层契约稳定性
一旦在方法签名里写 throws ValidationException, IOException,就等于把实现细节强加给契约:
- 所有实现类必须显式处理或继续抛出,无法隐藏内部技术选型(比如数据库换为内存缓存后,还该抛 SQLException 吗?)
- 每个调用方都被迫写 try-catch 或向上声明,业务代码被异常模板淹没,可读性下降
- 新增一个业务错误类型(如 AccountFrozenException),就得改接口、改所有实现、通知所有下游——开闭原则形同虚设
运行时异常才是语义解耦的合理载体
用继承 RuntimeException 的统一异常类(如 CommonException)承载业务错误,接口保持干净:
- 方法签名不带 throws,实现自由选择何时、为何、以何种结构抛出异常
- 异常本身携带 code、msg、status 等字段,由全局异常处理器统一转成标准响应体
- 调用方按需捕获特定子类(如 UserNotFoundException),或统一处理 CommonException,粒度可控
兼容性靠文档与SDK,不靠 throws 关键字
所谓“兼容”,本质是错误语义的一致理解,而非编译期强制绑定:
- OpenAPI 文档明确定义各 HTTP 状态码对应哪些 error_code 及含义,前端/合作方据此解析
- 提供 Java SDK 封装远程调用:内部消化 HttpClientErrorException、TimeoutException 等受检异常,对外只抛业务意义明确的运行时异常
- 版本升级时只扩展错误码枚举,保留旧码语义不变,下游无需改任何解析逻辑
对接老系统时,用适配器吞掉受检异常
当必须集成遗留模块或第三方 SDK(其方法强制 throws SQLException、RemoteException):
- 不修改对外接口定义,另写一层适配器实现该接口
- 适配器内部 try-catch 这些受检异常,转为 CommonException 并附带原始 cause
- 干净接口照常使用,脏活全由适配器消化,边界清晰、职责单一











