Java断言默认关闭,需用-ea参数启用,仅适用于开发调试阶段校验内部状态,不可替代业务逻辑中的空值检查;双参数形式可提供关键调试信息。

Java断言默认是关闭的,assert语句根本不会执行
很多人写了assert x != null就以为能拦住空值,结果上线后照样崩——因为JVM默认禁用断言。它只在开发调试阶段起作用,且必须显式开启:java -ea MyApp(-ea即-enableassertions)。生产环境通常不加这个参数,所以assert绝不能替代业务逻辑里的if (x == null) throw new IllegalArgumentException()。
常见错误现象:
• 单元测试里断言没触发,怀疑语法写错
• 打成jar包运行时,所有assert静默失效
• 误把assert当防御性编程手段,线上出NPE才反应过来
- 开发期可配合IDE配置:IntelliJ在Run Configuration里勾选「Enable assertions」;Eclipse在Arguments → VM arguments填
-ea - 只用于校验「理论上绝不该发生」的内部状态,比如私有方法入参已由上层保证非空,此处再断言只是防代码被改坏
- 不要在
assert里放有副作用的表达式,如assert list.remove(0) > 0——关闭断言时这行直接跳过,逻辑就变了
assert的两种写法差异直接影响调试信息质量
单参数形式assert condition;失败时只抛AssertionError,无任何上下文;双参数形式assert condition : detailMsg;会在异常中带上detailMsg,这是定位问题的关键。
使用场景:
• 调试循环内变量关系:assert i <br>• 校验私有方法不变量:<code>assert size >= 0 && size
立即学习“Java免费学习笔记(深入)”;
- 推荐始终用双参数形式,哪怕只是写个字符串字面量,比如
assert obj != null : "obj unexpectedly null in calculate()" -
detailMsg支持任意表达式,但避免复杂计算或IO操作——断言本就不该影响主流程性能 - 注意字符串拼接开销:高频路径中,用
String.format或延迟求值方式(如Supplier)更稳妥
断言 vs Objects.requireNonNull:别混用,职责完全不同
Objects.requireNonNull是运行时强制检查,无论JVM参数如何都会执行,并抛出明确的NullPointerException;而assert是可开关的调试钩子。两者根本不在一个维度上。
典型误用:
• 在public API方法开头写assert param != null——用户传null时什么都不会发生
• 把requireNonNull换成assert来“减少开销”——结果失去契约保障
- 对外暴露的方法、构造器、setter,必须用
Objects.requireNonNull或显式if校验 -
assert只出现在private/protected方法内部,或单元测试的验证逻辑中 - 性能影响:二者都极轻量,但
requireNonNull多一次方法调用和异常对象创建;assert在关闭状态下零成本——但这不是选它的理由,而是它的限制
IDE和构建工具可能悄悄干扰断言行为
IntelliJ默认在「Build, Execution, Deployment → Compiler → Java Compiler」里勾选「Enable compiler assertion checking」,但这只影响编译期是否允许assert语法,不影响运行时;Gradle的test任务默认不启用断言,需手动配置jvmArgs = ['-ea']。
容易踩的坑:
• Maven Surefire插件默认关闭断言,不加配置的话,mvn test中的assert全失效
• Lombok的@NonNull生成的是requireNonNull调用,不是assert,别指望它响应-ea
- Maven中启用测试断言:在
pom.xml的surefire插件配置里加<argline>-ea</argline> - Spring Boot应用若用
spring-boot-maven-plugin启动,同样要给run目标配jvmArguments = "-ea" - CI流水线中,确保所有JVM启动命令(包括Jacoco、Pitest等工具)都明确声明
-ea或-da,避免依赖默认值
断言真正的价值不在“报错”,而在表达开发者对代码状态的确定性预期。一旦开始怀疑某个条件可能不成立,就该把它写成明文契约——要么用不可绕过的requireNonNull,要么用可开关的assert并确保调试环境开着它。忘了开-ea,比写错断言更常见也更难排查。










