【编程规范】断言(assert)
用错误处理代码处理可能发生的情况 用断言处理理论上绝不应该发生的情况
什么是断言?
断言是一种开发期自检机制,用于验证程序中的内部假设是否成立。
可以把断言理解为:
👉 可执行的注释 👉 开发阶段的安全网 👉 用于捕获逻辑错误,而不是处理业务错误
断言失败说明:
❗ 程序存在 Bug ❗ 某个“不可能发生”的情况发生了
此时应立即终止程序,而不是尝试恢复。
断言 vs 错误处理
| 场景 | 应使用 |
|---|---|
| 用户输入错误 | if / 异常处理 |
| 外部数据不可信 | if / 异常处理 |
| 网络 / IO 失败 | 异常处理 |
| 内部逻辑不变量被破坏 | assert |
示例:
// ❌ 错误:用 assert 检查用户输入
assert age >= 0;
// ✔ 正确:使用业务校验
if (age < 0) {
throw new IllegalArgumentException("age must >= 0");
}
断言的语法(以 Java 为例)
assert booleanExpression;
assert booleanExpression : errorMessage;
行为:
- 表达式为
true→ 程序继续执行 - 表达式为
false→ 抛出AssertionError并终止
⚠ Java 默认关闭断言,需使用 -ea 启用
断言的典型使用位置
1️⃣ 校验内部参数状态
用于验证函数调用方已保证的前置条件
int resetBufferSize(int newSize) {
assert newSize >= 0;
assert newSize <= MAX_BUFFER_SIZE;
...
}
注意:
如果 newSize 来自用户输入,则应使用 if + 异常,而不是 assert
2️⃣ 验证不变量(Invariant)
assert balance >= 0 : "Balance should never be negative";
用于确保:
- 数据结构状态合法
- 对象生命周期正确
- 算法中间状态合理
3️⃣ 不可达代码(Unreachable Code)
switch (status) {
case READY:
case RUNNING:
case STOPPED:
break;
default:
assert false : "Unknown status";
}
一次只做一件事
❌ 不推荐:
assert(nOffset >= 0 && nOffset + nSize <= m_nInformationSize);
问题:
- 失败时无法快速定位是哪一个条件错误
✔ 推荐:
assert nOffset >= 0;
assert nOffset + nSize <= m_nInformationSize;
断言不能有副作用
断言在很多语言中只在调试模式启用,发布版本会被移除。
因此:
❌ 错误写法:
assert i++ < 100; // 发布版不会执行 i++
✔ 正确写法:
assert i < 100;
i++;
原则:
👉 断言表达式必须是纯判断,不得修改状态
性能说明
断言的开销主要来自:
- 表达式计算
- 错误信息构造
- 失败时的栈跟踪
因此:
- 高频路径(热点循环)中应谨慎使用
- 复杂字符串拼接应避免
例如:
// ❌ 即使断言关闭,也会构造字符串
assert x > 0 : "value = " + heavyToString(obj);
可改为:
assert x > 0 : obj;
或仅在调试代码中使用。
与防御式编程的区别
| 项目 | 断言 | 防御式编程 |
|---|---|---|
| 目的 | 捕获程序员错误 | 防止系统崩溃 |
| 是否面向用户 | 否 | 是 |
| 失败后行为 | 直接终止 | 可恢复 |
| 是否在生产启用 | 通常关闭 | 必须启用 |
一句话:
👉 断言保护开发者 👉 防御式编程保护系统
最佳实践
✔ 用于验证内部不变量 ✔ 用于标记不可能发生的分支 ✔ 每个断言只检查一个条件 ✔ 断言表达式必须无副作用 ✔ 不用于用户输入校验 ✔ 不依赖断言保证业务逻辑正确
代码风格建议:
assert condition : "明确的错误说明";
并与业务代码保持视觉分隔:
assert size >= 0;
process(size);
反模式(常见误用)
❌ 用断言替代参数校验 ❌ 在断言中写函数调用(有副作用) ❌ 在生产逻辑中依赖断言 ❌ 在热点循环中滥用断言 ❌ 使用复杂布尔表达式
总结
断言的本质:
👉 用于验证“程序员的假设” 👉 发现 Bug 时立即失败 👉 不参与业务逻辑
使用口诀:
#java#对内用断言,对外用异常 断言不改状态,只做判断
java知识详解