# apiAssert
**Repository Path**: min1854/api-assert
## Basic Information
- **Project Name**: apiAssert
- **Description**: 校验、断言框架
- **Primary Language**: Java
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 5
- **Forks**: 2
- **Created**: 2022-04-01
- **Last Updated**: 2026-06-02
## Categories & Tags
**Categories**: Uncategorized
**Tags**: Java
## README
# Api-Assert
[](https://central.sonatype.com/artifact/io.github.min1854/apiAssert)
[](./LICENSE)
> 轻量级 Java 断言框架 —— 让条件校验更优雅,告别重复的 `if-throw` 代码
- [GitHub 地址](https://github.com/min1854/apiAssert)
- [Gitee 地址](https://gitee.com/min1854/api-assert)
---
## 📖 目录
- [简介](#简介)
- [快速开始](#快速开始)
- [检查器对比](#检查器对比)
- [详细用法](#详细用法)
- [版本说明](#版本说明)
- [常见问题](#常见问题)
- [相关链接](#相关链接)
---
## 简介
在日常开发中,我们经常需要编写这样的代码:
```java
if (req == null) {
throw new RuntimeException("参数不可为空");
}
if (req.getId() == null) {
throw new RuntimeException("id 不可为空");
}
```
**Api-Assert** 将这些重复的条件判断封装为链式调用,让代码更加简洁、可读、易维护。
```java
FunctionApiAssert apiAssert = FunctionApiAssert.create(RuntimeException::new);
apiAssert.isNull(req, "参数不可为空")
.isNull(req.getId(), "id 不可为空");
```
### 核心设计理念
> 将业务代码的执行流程抽象为一个 `assert` 对象,通过流程划分保证代码质量的下限,提高可维护性。
---
## 快速开始
### 1. 添加依赖
**Maven**
```xml
io.github.min1854
apiAssert
2.0.5
```
**Gradle**
```gradle
implementation 'io.github.min1854:apiAssert:2.0.5'
```
### 2. 第一个示例
```java
import io.github.min1854.apiAssert.check.FunctionApiAssert;
public class OrderService {
// 将断言声明为常量,避免重复创建
private static final FunctionApiAssert ASSERT =
FunctionApiAssert.create(IllegalArgumentException::new);
public void createOrder(CreateOrderRequest req) {
ASSERT.isNull(req, "请求参数不能为空")
.isNull(req.getUserId(), "用户 ID 不能为空")
.isTrue(req.getAmount() <= 0, "金额必须大于 0");
// 业务逻辑...
}
}
```
如果任一条件成立,会立即抛出 `IllegalArgumentException`,并携带对应的错误信息。
---
## 检查器对比
| 检查器 | 异常创建方式 | 是否链式 | 是否立即抛出 | 适用场景 |
| --- | --- | --- | --- | --- |
| `FunctionApiAssert` | 函数式(由调用者提供) | ✅(多个条件校验) | ✅ | 常量定义、工具类、简单参数校验 |
| `OperateApiAssert` | 函数式 | ✅(支持对象属性校验) | ✅ | 复杂对象校验、链式属性判断 |
| `EnumFunctionApiAssert` | 枚举消息(函数式) | ✅ | ✅ | 国际化场景、统一错误码管理 |
| `EnumOperateApiAssert` | 枚举消息 | ✅ | ✅ | 对象属性校验 + 国际化错误码 |
| `FirstApiAssert` | 无(仅记录) | ✅ | ❌(需手动调用) | 收集多个校验结果,最后统一处理 |
| `ReflectionApiAssert` | 反射 | ✅ | ✅ | 异常类型在运行时才能确定 |
### 如何选择?
- **简单参数校验** → `FunctionApiAssert`
- **对象属性校验**(如 `req.getXxx()`) → `OperateApiAssert`
- **需要国际化或错误码** → `EnumFunctionApiAssert` / `EnumOperateApiAssert`
- **需要收集所有错误后统一处理** → `FirstApiAssert`
---
## 详细用法
### 1. FunctionApiAssert —— 基础条件校验
```java
FunctionApiAssert assert = FunctionApiAssert.create(RuntimeException::new);
assert.isNull(obj, "对象不能为空")
.nonNull(obj, "对象必须为空")
.isTrue(flag, "条件必须为 true")
.isFalse(flag, "条件必须为 false")
.isEmpty(collection, "集合不能为空");
```
### 2. OperateApiAssert —— 对象属性校验
```java
// 创建一个带有被测对象的校验器
OperateApiAssert assert = OperateApiAssert.create(user, RuntimeException::new);
// Lambda 方式获取属性,类似 MyBatis-Plus 的 LambdaWrapper
assert.nonNull(User::getName, "用户名不能为空")
.isTrue(User::getActive, "用户未激活")
.isEmpty(User::getOrders, "订单列表不为空");
```
### 3. then() —— 对象转换与继续校验
```java
OperateApiAssert userAssert = OperateApiAssert.create(user, RuntimeException::new);
// 获取用户的 ID 并继续校验
OperateApiAssert idAssert = userAssert.then(User::getId);
idAssert.isTrue(id -> id > 0, "用户 ID 必须大于 0");
```
### 4. process() —— 校验前/后插入业务逻辑
```java
OperateApiAssert assert = OperateApiAssert.create(user, RuntimeException::new);
assert.process(() -> {
System.out.println("校验前置处理");
})
.process(userObj -> {
System.out.println("当前用户: " + userObj);
})
.process((userObj, self) -> {
self.isNull(userObj.getParent(), "父级用户不存在");
});
```
### 5. 完整示例
```java
public class DemoService {
private static final FunctionApiAssert ASSERT =
FunctionApiAssert.create(IllegalArgumentException::new);
public void processOrder(OrderReq req) {
OperateApiAssert assert =
OperateApiAssert.create(req, IllegalArgumentException::new);
assert.isNull(OrderReq::getOrderId, "订单 ID 不能为空")
.isTrue(OrderReq::getAmount > 0, "金额必须大于 0")
.process(() -> validateInventory(req))
.then(OrderReq::getOrderId)
.isTrue(id -> id.startsWith("ORD"), "订单 ID 格式错误");
// 业务逻辑...
}
private void validateInventory(OrderReq req) {
// 库存校验逻辑
}
}
```
---
## 版本说明
### ⚠️ 2.0 破坏性变更
2.0 版本进行了完全重构,与 1.x **不兼容**:
- 包名变更(1.x 与 2.x 不同)
- 继承体系重构
- 部分 API 方法签名调整
> 如果你正在使用 1.x 版本,建议阅读 [迁移指南](./MIGRATION.md)(待补充)
### 最新版本:2.0.5
- **优化**:所有 `message` 仅在条件成立后执行,避免无意义的字符串拼接开销
### 历史版本
| 版本 | 主要变更 |
| --- | --- |
| 2.0.4 | 包名变更为 `io.github.min1854` |
| 2.0.3 | 元组类重构,新增新的元组类 |
| 2.0.2 | `handler` 默认方法提升至 `StandardApiAssert` |
| 2.0.1 | `OperationApiAssert` 增加 `handler` 默认方法 |
| 2.0.0 | 完全重构,新增枚举校验器 |
> 完整版本日志请查看 [CHANGELOG.md](./CHANGELOG.md)
---
## 常见问题
### Q1: 这些校验器是线程安全的吗?
- `FunctionApiAssert` 是**无状态的**,可以作为常量在多个线程中共享
- `OperateApiAssert` 持有具体对象实例,**不应跨线程共享**
### Q2: 可以自定义异常类型吗?
可以。`FunctionApiAssert.create(Supplier extends RuntimeException>)` 支持传入任何 `RuntimeException` 的子类。
### Q3: 条件成立后才获取 message,如果 message 是动态生成的会有性能问题吗?
不会。框架保证 message 只在条件成立时执行,不会产生不必要的开销。
### Q4: 与 Spring 的 Assert 工具类有什么区别?
| 特性 | Spring Assert | Api-Assert |
| --- | --- | --- |
| 链式调用 | ❌ | ✅ |
| Lambda 属性获取 | ❌ | ✅ |
| 自定义异常 | 有限 | 完全支持 |
| 对象转换继续校验 | ❌ | ✅(`then` 方法) |
---
## 相关链接
- [GitHub 仓库](https://github.com/min1854/apiAssert)
- [Gitee 镜像](https://gitee.com/min1854/api-assert)
- [问题反馈](https://github.com/min1854/apiAssert/issues)
- [更新日志](./CHANGELOG.md)
---
## License
Apache 2.0