Bug记录:Lombok @Builder 注解的两大陷阱及解决方案

问题概述:

Lombok 的 @Builder 注解极大地简化了“建造者模式”的代码编写,但其默认行为存在两个非常隐蔽的陷阱:

陷阱一:无参构造函数消失

现象:当一个类同时使用 @Data 和 @Builder 后,原本可用的无参构造函数 new Entity() 突然不可用,编译报错。

陷阱二:字段默认值(初始化)失效

现象:在字段声明时设置的默认值(如 String status = “open”;),通过 Builder 创建对象时,若未显式设置该字段,其值将为 null 而非预期的 “open”。

陷阱一:无参构造函数消失

复现步骤

编写一个同时使用 @Data 和 @Builder 的类。

@Data
@Builder
public class User {
    private String name;
    private Integer age;
}

尝试在其他地方使用无参构造

User user = new User(); // 编译错误:找不到符号 User()

原因分析

  • @Data 会生成一个 @RequiredArgsConstructor。如果类中没有 final 或@NonNull 的字段,这个构造器就是无参的。此时,单独使用 @Data 是完全可以无参构造的。

  • @Builder 注解需要基于一个全参构造函数来工作。当它发现你没有显式提供任何构造器时,它会主动生成一个私有的、包含所有字段的全参构造函数。

  • @Builder 的生成行为取代了 @Data 生成 @RequiredArgsConstructor 的逻辑。最终,编译后的类中只剩下 @Builder 生成的私有全参构造器,导致无参构造器确实“消失”了。

解决方案
显式声明所需的全部构造器,避免 Lombok 的默认行为产生冲突。

@Data
@Builder
@NoArgsConstructor // 显式指定:我需要无参构造
@AllArgsConstructor // 显式指定:我需要全参构造(让Builder直接使用这个现成的)
public class User {
    private String name;
    private Integer age;
}

陷阱二:字段默认值(初始化)失效

复现步骤

编写一个带有字段默认值的类并使用 Builder。

@Data
@Builder
public class Order {
    private Long id;
    private String status = "open"; // 期望的默认值
}

使用 Builder 创建对象,但不设置 status 字段。

Order order = Order.builder().id(1L).build();
System.out.println(order.getStatus()); // 输出:null (预期是 "open")

原因分析

  • 字段的默认值 = "open"是在类的构造函数内部执行的。

  • @Builder 的 build() 方法本质上是调用了类的全参构造函数,并将 Builder 对象内部的字段值作为参数传入。关键点在于:构造函数会无条件使用传入的参数。

  • 如果你没有调用 .status(…) 方法,Builder 对象内部的 status 字段值就是 null。在调用 build() 时,执行的是 new Order(id, status),这个 null 被传入了构造函数,完全覆盖了类定义中 = “open” 的初始化操作。

解决方案
使用 Lombok 提供的 @Builder.Default 注解。

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Order {
    private Long id;
    
    @Builder.Default // 使用此注解标记
    private String status = "open";
}

@Builder.Default 的原理:它会指示 Lombok 在生成的 Builder 类中,预先将这个字段初始化为指定的默认值。如果后续没有显式设置该字段,build() 方法就会使用这个预先存在的默认值,而不是 null。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值