java断言是仅用于开发调试的内部逻辑自检机制,需显式启用(-ea),失败抛assertionerror且不可捕获,禁止有副作用,不能替代业务校验。

Java 的断言(Assertion)不是运行时校验工具,而是一种仅在开发调试阶段启用的逻辑自检机制。它不处理用户输入、外部依赖或业务异常,只用于验证程序员自己写的“绝不可能为假”的内部假设——比如算法中间状态、私有方法入参、循环不变量等。一旦失败,说明程序已进入不可信状态,应立即中断,而非尝试恢复。
断言必须显式开启,否则等于没写
Java 默认完全禁用所有 assert 语句,JVM 在类加载时直接跳过它们,连条件表达式都不执行。这意味着:
- 不加 -ea(即
-enableassertions)参数,assert false;也不会抛错、不会中断 - IDE 运行配置默认不带该参数,IntelliJ 和 Eclipse 都需手动在 Run Configuration → VM options 中填写
-ea - Gradle 测试任务也默认关闭,需显式配置:
test { jvmArgs = ['-ea'] } - 可精细控制范围:全局启用用
-ea;只对某包启用写-ea:com.example;禁用某个类则用-da:com.example.DebugHelper
断言失败抛的是 AssertionError,不是 Exception
AssertionError 继承自 Error,属于严重错误范畴,设计上不可捕获、不应恢复:
- 别写
try { assert x != null; } catch (AssertionError e) { ... }—— 这违背断言本意 - 别在方法签名里声明
throws AssertionError—— 编译器会警告,且毫无意义 - 它的作用是“立刻暴露矛盾”:比如状态机跳到非法状态、递归退出条件未满足、缓存一致性被破坏
- 如果你总想“处理”断言失败,说明这里本该用
Objects.requireNonNull()或自定义业务异常
断言不能有副作用,否则生产环境行为不一致
因为断言在生产中被跳过,任何附着其上的逻辑都会消失,导致行为割裂:
- ❌ 错误:
assert list.remove(0) > 0;—— 上线后remove()不执行,列表内容不变,逻辑错乱 - ❌ 错误:
assert logger.info("checking x=" + x);—— 日志在生产中彻底丢失 - ✅ 正确:
assert x > 0 : "x must be positive, got " + x;—— 条件纯判断,提示信息无副作用 - ⚠️ 注意双参数形式中第二参数的求值时机:只在断言失败时才计算,所以
assert list != null : "size=" + list.size();在list为null时会先抛NullPointerException,而非预期的AssertionError
生产环境必须禁用,且不能替代业务校验
断言不是 if-throw 的简写,更不是上线后的安全网:
- 公共方法入口的参数检查(如
public void process(String input))必须用if (input == null) throw new IllegalArgumentException(...),绝不能用assert input != null; - 检查文件是否存在、网络是否可达、数据库连接是否正常……这些都属外部不确定性,必须用显式异常处理
- Android 平台部分版本甚至完全忽略断言指令,依赖它会导致跨平台行为差异
- 真正适合断言的地方很窄:私有方法内部状态断点、复杂算法阶段性验证、单元测试中的中间断言(配合
-ea)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











