Lombok @Builder 不支持在生成代码中直接插入 throw,但可在自定义 build() 方法中进行非空校验并抛出异常;推荐禁用自动生成 build(),手动实现校验逻辑。

在 Lombok @Builder 生成的 builder 方法中,throw 无法直接“插入”到自动生成的代码里——因为 Lombok 不提供钩子让你在 builder 构建过程中自动抛异常。但你可以通过几种**可控且符合 Java 实践**的方式,在 builder 构建完成、调用 build() 时做非空校验,并用 throw 抛出异常。
使用 @Builder(builderMethodName = "...") + 自定义 build() 方法
这是最推荐、最清晰的做法:禁用 Lombok 自动生成的 build(),自己写一个带校验逻辑的 build() 方法,里面用 throw 主动抛异常。
示例:
@Builder(builderMethodName = "builder")
public class User {
private final String name;
private final Integer age;
// 手动定义 build(),Lombok 不再生成它
public User build() {
if (name == null || name.trim().isEmpty()) {
throw new IllegalArgumentException("name 不能为空");
}
if (age == null || age <= 0) {
throw new IllegalArgumentException("age 必须为正整数");
}
return new User(name, age);
}
// 私有构造器(Lombok builder 需要)
private User(String name, Integer age) {
this.name = name;
this.age = age;
}
}
这样调用时:
立即学习“Java免费学习笔记(深入)”;
User user = User.builder()
.name("Alice")
.age(25)
.build(); // ✅ 正常通过
User.builder()
.name(null)
.age(30)
.build(); // ❌ 抛 IllegalArgumentException
配合 @AllArgsConstructor + @RequiredArgsConstructor(更轻量)
如果你不需要全字段 builder,只对必填字段校验,可以用 @RequiredArgsConstructor(配合 final 或 @NonNull),Lombok 会在构造器里自动生成非空检查并 throw。
示例:
@RequiredArgsConstructor
public class User {
@NonNull private final String name;
private final Integer age;
// 注意:@NonNull 字段会在构造器中生成类似:
// if (name == null) throw new NullPointerException("name is marked non-null but is null");
}
此时你仍可搭配 @Builder,但需注意:Lombok 默认会为 @NonNull 字段在 builder 的 setter 中也加空检查(从 v1.18.20+ 开始默认启用)。也就是说:
- 调用
.name(null)时就会立即抛NullPointerException(不是等到build()) - 这个行为由
lombok.nonNull配置或@NonNull注解触发,底层就是用throw
用 static builder + 链式校验(适合复杂规则)
如果校验逻辑较重(比如依赖多个字段组合判断),可以定义静态 builder 类,在 build() 前做统一检查:
@Builder
public class Order {
private final String orderId;
private final BigDecimal amount;
private final String currency;
public static class OrderBuilder {
private String orderId;
private BigDecimal amount;
private String currency;
public Order build() {
if (amount != null && amount.compareTo(BigDecimal.ZERO) < 0) {
throw new IllegalArgumentException("金额不能为负数");
}
if (amount != null && currency == null) {
throw new IllegalArgumentException("currency 不能为空,当 amount 已设置时");
}
return new Order(orderId, amount, currency);
}
// 其他 setter...(可手写或靠 Lombok 生成)
}
}
不过这种方式要放弃 Lombok 自动生成 builder 类,灵活性下降,一般只在特殊场景用。
避免踩坑:不要试图修改 Lombok 生成的 builder 源码
Lombok 生成的代码在编译期注入,你无法在源码中编辑它;也不能用 AOP 或代理拦截 builder 的 setter——因为 builder 是普通对象,没有接口或运行时增强点。强行 hack 不仅难维护,还容易和 Lombok 版本冲突。
真正可靠的方式只有两个:
- 让校验发生在
build()调用时(自定义 build 方法) - 让校验发生在字段赋值时(用
@NonNull触发 Lombok 自动生成的throw)
两种都用到了 throw,也都与 @Builder 兼容,只是时机和粒度不同。


















