应优先继承runtimeexception,除非调用方必须主动处理外部可恢复问题;exception用于需强制声明的外部异常(如io、sql),runtimeexception用于内部逻辑错误(如参数非法、状态冲突),自定义异常须提供两个标准构造器。

关键看调用方是否必须主动处理——该强制应对就选 Exception,该快速暴露问题就选 RuntimeException。
看异常性质:是外部可恢复问题,还是内部逻辑错误
如果问题来自外部且调用方能做有意义的响应,比如重试、降级、提示用户或切换策略,就继承 Exception:
- 文件读取失败(IOException)
- 数据库连接中断(SQLException)
- 第三方接口超时或返回 503(可封装为 ServiceUnavailableException)
如果问题源于代码本身,比如参数非法、状态不符、空值误用,就继承 RuntimeException:
- 传了 null 或负数年龄 → IllegalArgumentException
- 对已关闭的流再读取 → IllegalStateException
- 订单已取消却调用发货 → 自定义 OrderInvalidStateException
看方法签名和调用链是否干净
继承 Exception 会强制所有上层方法加 throws 或 try-catch,容易污染接口:
- 已有多个受检异常时,新增一个需谨慎评估必要性
- 若实际只统一记录日志+返回错误码,那强制声明反而掩盖设计意图
继承 RuntimeException 不干扰签名,适合由全局处理器(如 Spring 的 @ControllerAdvice)集中捕获:
- 多数业务异常(余额不足、权限拒绝、手机号格式错)都走这条路
- 开发阶段易暴露问题,线上也便于统一兜底
自定义异常怎么定父类
默认优先继承 RuntimeException,除非你能明确说出“为什么每个调用方都必须声明 throws”:
- 需要调用方决策重试/回滚/切换数据源 → 继承 Exception
- 只是校验失败、状态冲突、参数越界 → 继承 RuntimeException
无论选哪个,都必须提供两个构造器:
- MyException(String message)
- MyException(String message, Throwable cause) —— 否则嵌套异常信息丢失,排查困难
别被名字误导,只看继承树
是否受检,跟类名里有没有 “Runtime” 完全无关。唯一判断标准是:
- 它是不是 RuntimeException 或 Error 的子类?是 → 不强制处理
- 它直接继承 Exception 且不是 RuntimeException 分支?→ 必须处理
在 IDE 中按住 Ctrl 点进异常类源码,一眼看清父类链,比猜名字可靠得多。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











