@Builder 是 Lombok 注解,用于自动生成构造器模式的代码。主要作用:
1. 替代多个构造器
// 不使用 @Builder
public class User {
private String name;
private int age;
private String email;
public User(String name) { this.name = name; }
public User(String name, int age) { this.name = name; this.age = age; }
// 更多构造器...
}
// 使用 @Builder
@Builder
public class User {
private String name;
private int age;
private String email;
}
2. 链式调用设置属性
User user = User.builder()
.name("张三")
.age(25)
.email("zhangsan@example.com")
.build();
3. 核心优势
- 可读性强:通过方法名明确参数含义
- 灵活性高:可以只设置需要的参数
- 不变性支持:与
@Data或手动 getter 配合 - 线程安全:通常用于构建不可变对象
4. 常用配置选项
// 设置默认值
@Builder
public class User {
@Builder.Default
private int status = 1;
}
// 与 @AllArgsConstructor 配合
@Builder
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class User {
private String name;
private int age;
}
// 使用 toBuilder 创建副本
@Builder(toBuilder = true)
public class User {
private String name;
private int age;
}
5. 编译后生成的代码
Lombok 会在编译时生成:
User.UserBuilder内部类builder()静态方法build()方法- 所有字段的 setter 方法(返回 builder 本身)
6. 适用场景
- DTO/VO 对象
- 配置类
- 需要多个可选参数的复杂对象
- 测试数据构造
7. 注意事项
@Builder
public class User {
// 如果有 final 字段,必须初始化
private final String id = UUID.randomUUID().toString();
// 如果有 @Builder.Default,不能在构造器中重新赋值
@Builder.Default
private Date createTime = new Date();
}
@Builder 简化了对象创建,特别是当对象有很多可选参数时,避免了编写多个重载构造器或冗长的 setter 调用。
@Builder.Default 是 Lombok @Builder 注解的配套注解,用于设置 Builder 的默认值。
1. 基本用法
@Builder
public class User {
private String name;
@Builder.Default
private Integer age = 18; // 设置默认值
@Builder.Default
private Boolean active = true;
// 如果没有 @Builder.Default,默认值不会被 Builder 使用
private String role = "user"; // ❌ Builder 会忽略这个默认值
}
2. 为什么需要 @Builder.Default
@Builder
public class User {
private String name;
private int age = 18; // 字段初始化
public static void main(String[] args) {
User user = User.builder()
.name("张三")
.build();
System.out.println(user.getAge()); // 输出: 0 ❌ 不是 18!
}
}
问题:没有 @Builder.Default 时,字段初始值会被 Builder 忽略。
3. 正确的用法
@Builder
public class User {
private String name;
@Builder.Default
private int age = 18; // ✅ Builder 会使用这个默认值
@Builder.Default
private List<String> hobbies = new ArrayList<>();
@Builder.Default
private Date createTime = new Date(); // 每次构建时都是新对象
}
// 使用
User user1 = User.builder()
.name("张三")
.build(); // age=18, hobbies=[], createTime=当前时间
User user2 = User.builder()
.name("李四")
.age(25) // 可以覆盖默认值
.build();
4. 集合和对象的特殊处理
@Builder
public class Config {
// 集合类型 - 推荐方式
@Builder.Default
private List<String> permissions = new ArrayList<>(Arrays.asList("read", "write"));
// 防止空指针
@Builder.Default
private Map<String, Object> metadata = new HashMap<>();
// 复杂对象
@Builder.Default
private Address address = Address.builder()
.city("北京")
.country("中国")
.build();
}
5. 配合其他注解使用
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Product {
private Long id;
@Builder.Default
private String status = "DRAFT";
@Builder.Default
private LocalDateTime createdAt = LocalDateTime.now();
}
6. 继承中的使用
@SuperBuilder
public class Parent {
@Builder.Default
protected String parentField = "parent default";
}
@SuperBuilder
public class Child extends Parent {
@Builder.Default
private String childField = "child default";
}
7. 与 toBuilder 一起使用
@Builder(toBuilder = true)
public class Order {
private Long id;
@Builder.Default
private String status = "NEW";
public Order cancel() {
return this.toBuilder()
.status("CANCELLED") // 可以修改 @Builder.Default 的字段
.build();
}
}
8. 注意事项
@Builder
public class Example {
// ❌ 错误:final 字段不能用 @Builder.Default
@Builder.Default
private final String id = generateId(); // 编译错误
// ✅ 正确:final 字段直接初始化
private final String id = generateId();
// ❌ 错误:静态字段不能用 @Builder.Default
@Builder.Default
private static String type = "DEFAULT"; // 编译错误
// 线程安全问题
@Builder.Default
private Date timestamp = new Date(); // 每次构建都是新的 Date 对象
// 共享可变对象的风险
@Builder.Default
private List<String> items = new ArrayList<>();
public void addItem(String item) {
// 如果多个实例共享同一个默认列表,会有问题
// 但 @Builder.Default 每次都会创建新实例,所以安全
}
}
9. 工作原理
编译后生成的代码:
public class User {
private int age = 18;
public static class UserBuilder {
private boolean age$set = false; // 标志位,记录是否设置了 age
private int age$value;
public UserBuilder age(int age) {
this.age$value = age;
this.age$set = true;
return this;
}
public User build() {
User user = new User();
if (age$set) {
user.age = age$value; // 如果设置了,用设置的值
} else {
user.age = User.this.age; // 否则用默认值
}
return user;
}
}
}
总结:@Builder.Default 确保 Builder 模式中字段的默认值被正确使用,解决了普通字段初始化在 Builder 中被忽略的问题。