探索 Lombok 的 @Builder 和 @SuperBuilder:避坑指南(一)
文章目录
- @Builder 和 @SuperBuilder 的区别
- 坑点一:@Builder 不能直接用于继承结构
- 总结:在有继承关系的类上始终选择 `@SuperBuilder` 而不是 `@Builder`。
- 坑点二:@SuperBuilder 不能与 @NoArgsConstructor 直接共存
- 坑点三:@SuperBuilder 不支持构造器上的自定义逻辑
- 坑点四:@Builder.Default 在 @Builder 和 @SuperBuilder 中的局限
- 坑点五:字段类型为 Collection 时的深坑
- 小结
- 推荐阅读文章
Lombok 是 Java 中深受开发者欢迎的代码简化库,其中 @Builder 和 @SuperBuilder 是常用的注解,用于简化对象构建流程。但 @Builder 和 @SuperBuilder 的使用并非没有限制,稍有不慎就会出现一些意想不到的问题。本文就来深入探讨这两个注解的常见坑点和使用建议。
@Builder 和 @SuperBuilder 的区别
- @Builder:Lombok 的经典注解,用于为类生成 Builder 模式。它可以让我们更方便地创建对象,尤其是字段较多时。
- @SuperBuilder:Lombok 引入的增强版,支持子类和父类的 Builder 模式,特别适用于继承结构中构建对象的场景。
虽然 @SuperBuilder 是专为继承结构设计的,但在简单对象构建中也有一些有用特性。然而,这两个注解都有一些可能遇到的坑。
坑点一:@Builder 不能直接用于继承结构
问题:@Builder
不支持继承结构,如果直接在父类和子类上分别使用 @Builder
,会导致子类无法正常调用父类的字段,甚至在编译时直接报错。
解决方案:在继承结构中推荐使用 @SuperBuilder
,它专门为继承而设计,并能更好地支持父类与子类字段的构建。
// 父类
@SuperBuilder
public class Parent {
private String name;
}
// 子类
@SuperBuilder
public class Child extends Parent {
private int age;
}
// 使用
Child child = Child.builder().name("Alice").age(10).build();
总结:在有继承关系的类上始终选择 @SuperBuilder
而不是 @Builder
。
坑点二:@SuperBuilder 不能与 @NoArgsConstructor 直接共存
问题:有时我们需要 @NoArgsConstructor
无参构造函数,但如果直接与 @SuperBuilder
一起使用,会遇到编译冲突,导致构造器生成失败。
解决方案:可以借助 @NoArgsConstructor
的 force
属性,强制生成无参构造函数:
@NoArgsConstructor(force = true)
@SuperBuilder
public class Example {
private final String field;
}
这样 Lombok 会生成无参构造器,同时支持 @SuperBuilder
。
坑点三:@SuperBuilder 不支持构造器上的自定义逻辑
问题:如果希望在构建对象时进行额外的校验或初始化逻辑(例如计算某些属性),@SuperBuilder
默认生成的构造方法并不会支持这些自定义逻辑。
解决方案:需要在 @SuperBuilder
中使用 @Builder.Default
为字段提供默认值,或者手动添加私有构造器:
@SuperBuilder
public class Example {
private final String field;
@Builder.Default
private final int calculatedField = calculate();
private int calculate() {
// 自定义逻辑
return field.length();
}
}
这样可以确保默认值被正确初始化。
坑点四:@Builder.Default 在 @Builder 和 @SuperBuilder 中的局限
问题:@Builder.Default
是 Lombok 为 Builder 提供的默认值机制,但如果使用 @Builder.Default
来初始化某些字段,@Builder
会生成不必要的重复代码,这会导致不一致的行为。
解决方案:尽量避免在复杂逻辑中依赖 @Builder.Default
,如果确实需要默认值,建议直接使用构造函数来初始化,以避免误用。
坑点五:字段类型为 Collection 时的深坑
问题:当使用 @Builder.Default
为集合类型(如 List
、Set
)字段设置默认值时,Lombok 会为每次构建对象时提供一个共享的集合,这会导致并发问题和数据污染。
解决方案:应避免在集合类型字段上使用 @Builder.Default
,而是在构造函数中初始化集合,以确保每次构建新对象时都创建一个新的集合实例。
@SuperBuilder
public class Example {
private final List<String> list;
public Example() {
this.list = new ArrayList<>();
}
}
小结
- 有继承关系时,优先使用 @SuperBuilder。
- @SuperBuilder 和 @NoArgsConstructor 需要结合
force
属性使用。 - 避免在自定义逻辑初始化时依赖 @Builder。
- 集合类型字段尽量在构造函数中初始化,避免使用
@Builder.Default
。
通过这些小技巧,你可以有效避免 @Builder
和 @SuperBuilder
的踩坑问题,让代码更简洁、安全。希望本文能帮助你更好地使用 Lombok 的这些特性,让代码构建更加轻松。
推荐阅读文章
- 为什么用了 @Builder 反而报错?深入理解 Lombok 的“暗坑”与解决方案(二)
- 深入解析 Lombok 的实现原理:以 @Builder 为例的实战演示(三)
- 由 Spring 静态注入引发的一个线上T0级别事故(真的以后得避坑)
- 如何理解 HTTP 是无状态的,以及它与 Cookie 和 Session 之间的联系
- HTTP、HTTPS、Cookie 和 Session 之间的关系
- 什么是 Cookie?简单介绍与使用方法
- 什么是 Session?如何应用?
- 使用 Spring 框架构建 MVC 应用程序:初学者教程
- 有缺陷的 Java 代码:Java 开发人员最常犯的 10 大错误
- 把握Java泛型的艺术:协变、逆变与不可变性一网打尽
- Java Spring 中常用的 @PostConstruct 注解使用总结
- 如何自定义一个自己的 Spring Boot Starter 组件(从入门到实践)
- 解密 Redis:如何通过 IO 多路复用征服高并发挑战!
- 线程 vs 虚拟线程:深入理解及区别
- 深度解读 JDK 8、JDK 11、JDK 17 和 JDK 21 的区别
- 10大程序员提升代码优雅度的必杀技,瞬间让你成为团队宠儿!