Java断言仅用于开发调试,生产环境默认关闭,启用需显式添加-ea参数;断言语句不可有副作用,失败抛出AssertionError(不可捕获),适用场景限于私有方法内部状态、循环不变量等契约声明。

Java断言不是用来处理运行时异常的,它只在开发调试阶段启用时才生效,生产环境默认关闭——别把它当 if + throw 用,否则上线后断言全失效,问题照旧发生。
断言启用必须加 -ea JVM 参数
Java 默认禁用所有断言,哪怕写了 assert x != null;,不加参数就等于没写。JVM 启动时必须显式开启:
- 全局启用:
-ea(即-enableassertions) - 只对某个包启用:
-ea:com.example... - 禁用某个类的断言:
-da:com.example.ServiceTest
IDE 运行配置里容易漏掉这步——IntelliJ 默认不带 -ea,Eclipse 也得手动在 Run Configuration → Arguments → VM options 里填。Gradle 测试任务默认也不开,要加 test { jvmArgs = ['-ea'] }。
assert 表达式不能有副作用
断言语句在生产环境被跳过,所以任何带副作用的代码放进去会导致行为不一致:
立即学习“Java免费学习笔记(深入)”;
- ❌ 错误写法:
assert list.remove(0) > 0;—— 上线后这行不执行,list不变,逻辑错乱 - ❌ 错误写法:
assert log.debug("check value: " + x);——log.debug()不会调用,日志消失 - ✅ 正确写法:
assert x > 0 : "x must be positive";—— 纯判断 + 静态提示
编译器不会报错,但一旦关掉断言,你写的“检查”就变成空气,连带附着其上的逻辑一起蒸发。
断言失败抛出的是 AssertionError,不是 Exception
AssertionError 继承自 java.lang.Error,属于严重错误范畴,设计上就不该被捕获或恢复:
- ❌ 别这么写:
try { assert x != null; } catch (AssertionError e) { ... } - ❌ 也别在
throws声明里列它,IDE 会警告“unreported exception”但其实不该报 - ✅ 它的作用是立刻中断执行流,暴露逻辑矛盾,比如算法前提不成立、状态机进入非法状态
如果你发现自己想“处理”断言失败,说明这里本该是业务校验,该用 Objects.requireNonNull() 或自定义异常。
断言真正的价值不在“检查值”,而在于声明契约:这个条件**必须为真,否则程序已处于不可信状态**。很多人写完就忘加 -ea,或者把断言塞进公共方法入口做参数校验——这两处恰恰最该用明确异常。真正适合断言的地方很窄:私有方法内部中间状态、循环不变量、复杂算法的阶段性断点。用错地方,反而掩盖问题。










