我们可能经常在项目的单元测试或者一些源码中看到别人在使用assert关键字,当然也不只是Java语言,很多编程语言也都能看到,我们大概知道断言可以用于测试中条件的校验,但却不经常使用,本文总结了Java中该工具类的使用。
一、简介
断言:
“断言”一词源自英文 Assert,原意为“明确肯定地陈述”,或者说叫“断定某个条件必然成立”。在编程中,开发者通过断言明确肯定地声明某个条件应该成立,否则程序证明程序有缺陷。
二、assert 关键字
assert
是Java语言内置的关键字,在Java 1.4中被引入,用于在代码中进行条件断言,其语法形式如下:
// 形式1:简单条件检查
assert booleanExpression;
// 形式2:附带错误信息
assert booleanExpression : "Error message";
若表达式为false,则会抛出AssertionError
异常并终止程序,如果附带错误信息,则会将错误信息作为AssertionError
的详细信息输出,示例如下:
public class AssertExample {
public static void main(String[] args) {
validateAge(25); // 合法年龄
validateAge(-5); // 断言失败!
}
// 示例1:检查年龄合法性(简单断言)
public static void validateAge(int age) {
assert age >= 0 && age <= 120; // 断言年龄在合理范围
System.out.println("年龄验证通过: " + age);
}
// 示例1:检查年龄合法性(带错误信息)
public static void validateAge2(int age) {
assert age >= 0 && age <= 120 : ""; // 断言年龄在合理范围
System.out.println("年龄验证通过: " + age);
}
}
validateAage执行打印如下:
年龄验证通过: 25
Exception in thread "main" java.lang.AssertionError
at org.example.asserts.AssertExample.validateAge(AssertExample.java:15)
at org.example.asserts.AssertExample.main(AssertExample.java:11)
validateAage2执行打印如下:
年龄验证通过: 25
Exception in thread "main" java.lang.AssertionError: 年龄不合法
at org.example.asserts.AssertExample.validateAge2(AssertExample.java:20)
at org.example.asserts.AssertExample.main(AssertExample.java:11)
启用断言
默认情况下断言是关闭的,需通过JVM参数启用:
如IDEA在IntelliJ中,需在VM参数中添加-ea
(-enable assertions
命令的缩写)以生效, -da
表示禁止断言
适用场景
- 检查
private
方法的合法性(如非空、范围等)。 - 用于基类、工具类或框架代码,避免冗余的if判断
注意事项
- 断言错误是
AssertionError
,属于严重错误,通常不捕获。 - 如果参数由类自身逻辑控制(如内部调用),用
assert
替代 if。 - 如果参数来自外部不可控输入(如用户传递),仍需用
if
+throw
二、Assert 类
Assert
类通常来自测试框架或工具类(如JUnit
、Hutool
或Spring
的Assert
工具类),用于编写测试用例的断言。这些断言始终启用,与JVM参数无关。
以下是常见库中 Assert
类的详细介绍及用法示例:
JUnit 的 Assert 类
JUnit是一个广泛使用的单元测试框架,其中包含用于编写测试断言的方法
JUnit 4:org.junit.Assert
import static org.junit.Assert.*;
assertEquals("期望值", actualValue); // 验证相等性
assertTrue(condition); // 验证条件为真
assertNotNull(object); // 验证对象非空
assertArrayEquals(expectedArray, actualArray); // 验证数组相等
...
JUnit 5:org.junit.jupiter.api.Assertions
(支持更丰富的断言和错误信息)
import static org.junit.jupiter.api.Assertions.*;
assertEquals(expected, actual, () -> "动态错误信息"); // 支持Lambda表达式
assertThrows(Exception.class, () -> methodCall()); // 验证抛出异常
assertTimeout(Duration.ofSeconds(1), () -> task()); // 验证执行时间
...
Spring Framework 的 Assert 类
org.springframework.util.Assert
用途:用于方法参数校验和业务逻辑验证,通常在服务层或工具类中快速失败,校验失败时抛出 IllegalArgumentException
或 IllegalStateException
,适合生产环境使用,与测试框架的断言不同,Spring的 Assert
主要用于防御性编程而非单元测试
import org.springframework.util.Assert;
Assert.notNull(object, "对象不能为null"); // 非空校验
Assert.isTrue(condition, "条件必须为真"); // 条件校验
Assert.hasLength(str, "字符串不能为空"); // 字符串非空校验
Assert.state(condition, "状态不合法"); // 状态校验
...
示例:
public void processOrder(Order order) {
Assert.notNull(order, "订单对象不能为null");
Assert.isTrue(order.getAmount() > 0, "订单金额必须大于0");
// 处理逻辑
}
Apache Commons Lang 的 Validate 类
org.apache.commons.lang3.Validate
用途:类似于Spring的 Assert
,用于参数校验,但语法更灵活。
import org.apache.commons.lang3.Validate;
Validate.notNull(object, "参数 %s 不能为null", "object"); // 支持格式化消息
Validate.validState(condition, "状态无效: %s", errorMsg); // 状态校验
Validate.isTrue(condition, "条件不满足: %d", value); // 条件校验
...
示例:
public void setPrice(double price) {
Validate.isTrue(price >= 0, "价格不能为负数: %f", price);
this.price = price;
}
Hutool 的 Assert 类
Hutool 的 Assert
类似于 Spring 和 Apache Commons 的校验工具
import cn.hutool.core.lang.Assert;
Assert.notNull(obj); // 检查对象非 null
Assert.isTrue(condition); // 检查条件为 true
Assert.notEmpty(collection) // 检查集合非空
Assert.noNullElements(array) // 检查数组/集合中无 null 元素
特点:
- 无侵入性:不依赖 Spring 等框架,适合纯 Java 项目
- 简洁 API:方法命名直观(如
notBlank
直接校验字符串非空白) - 轻量级:只需引入
hutool-core
,适合中小型项目。
三、使用区别
在编写代码的时候,什么时候用assert
关键字,什么时候用Assert
类(如 JUnit、Spring、Hutool 等提供的),又什么时候可以直接if + throw来进行条件检查呢?
assert
关键字需要显示开启才能生效,一般用于测试调试程序时来使用,而且assert
断言失败后会导致程序的退出,一般生产环境代码校验我们可以用Assert
类,对于复杂逻辑和自定义的异常我们可以使用if
+ throw
来抛出异常
机制 | 适用场景 | 错误类型 | 是否默认启用 | 典型用途 |
---|---|---|---|---|
assert | 开发阶段内部逻辑检查 | AssertionError | 需要 -ea | 私有方法假设 |
Assert | 测试断言或生产参数校验 | 测试失败/IAE /NPE | 始终 | 单元测试、公共API输入校验 |
if +throw | 需要自定义异常或复杂校验逻辑 | 任意异常 | 始终 | 复杂或业务规则校验 |
总结:
断言作为一种编程机制,用于确保程序中特定条件为真,有助于简化代码并提高代码质量。我们可以根据不同需求选择合适的断言机制,从而在实际开发中更有效地提升代码的健壮性和可维护性。