@throws 标签必须与 throws 子句严格一致,仅声明受检异常及特定运行时异常(如 validationexception、responsestatusexception),描述需指向调用方可感知的具体条件,顺序按 throws 子句排列且不可合并。

@throws 标签不是摆设,它只在你写对了、用对了、上下游都认的时候才真正起作用。 错误的写法会让调用方误判异常类型,IDE 不提示,文档生成器忽略,甚至被 Lombok 的 @SneakyThrows 暗中绕过——最终问题全堆到运行时。
哪些异常必须写进 @throws
只声明 throws 子句里显式抛出的受检异常(checked exception),比如 IOException、SQLException;运行时异常(RuntimeException 及其子类)原则上不强制写,但以下情况例外:
- 该
RuntimeException是你 API 协议的一部分(如自定义的ValidationException),且调用方需主动捕获处理 - 方法内部用
throw new IllegalArgumentException(...)做参数校验,且这是你期望调用方阅读后规避的典型错误路径 - Spring MVC 控制器里抛出的
ResponseStatusException,虽是运行时异常,但前端依赖它映射 HTTP 状态码
别写 @throws NullPointerException——JDK 明确说它是“未声明的实现细节”,写了反而误导。
@throws 的写法必须和 throws 子句严格一致
这是最容易被忽略的同步断点。Javadoc 解析器不会做类型推导,@throws IOException 和 throws java.io.IOException 在某些旧版 Javadoc 工具里会被视为不同条目;更常见的是类名拼错或漏包名:
立即学习“Java免费学习笔记(深入)”;
/**
* 读取配置文件。
* @throws IOException 当文件不存在或不可读时
*/
public String loadConfig() throws IOException { ... }✅ 正确:异常类名与 throws 子句完全一致(包括包路径,除非已 import)
❌ 错误:@throws ioexception(大小写错)、@throws Exception(太宽泛)、@throws FileNotFoundException(但实际只声明了 IOException)
工具链影响:IntelliJ 默认只基于 throws 子句补全 try/catch,不看 @throws;但 Dokka、javadoc -doclet 工具会严格比对二者,不一致则跳过该条目。
多个异常怎么列?顺序有讲究吗
按方法签名中 throws 子句出现的顺序逐行写,每行一个 @throws。不要合并,不要省略中间项:
/**
* @throws IOException 当 I/O 失败时
* @throws SQLException 当数据库连接中断时
* @throws IllegalStateException 当状态非法时
*/
public void commitTransaction() throws IOException, SQLException, IllegalStateException { ... }为什么顺序重要?
- 部分 IDE(如 Eclipse)在生成 Javadoc 模板时会按此顺序填充占位符
- 团队若约定“受检异常优先、运行时异常靠后”,这个顺序就是契约的一部分
- 如果删掉中间某条
@throws,后续所有条目的序号和语义都会偏移,可读性直降
别用 @throws IOException, SQLException 这种逗号写法——Javadoc 规范不支持,会被整个忽略。
文档描述要指向“调用方能感知的动作”
别写“当底层发生错误时”,要写调用方能观察、能复现、能响应的具体条件:
- ❌ “当系统异常时” → 模糊,无法测试,无法拦截
- ✅ “当
configPath指向的文件被其他进程独占锁定时” → 调用方可提前加锁或重试 - ✅ “当
timeoutMs小于等于 0 时抛出IllegalArgumentException” → 调用方可做前置校验
描述里出现的变量名、参数名、路径,必须和方法签名中的一致,并用 <code> 包裹。这是人肉维护文档时最易出错的地方——参数改名了,@throws 描述却没同步。
复杂点在于:有些异常触发条件依赖外部状态(如网络抖动、DB 主从延迟),这类描述没法写死。此时宁可留空或写“取决于下游服务响应”,也别编造确定性条件。










