关注:CodingTechWork
引言
在 Java 项目中,使用 Lombok 的 @Builder 注解可以让我们用链式调用快速创建对象。通常我们会为一些字段在类中直接设置默认值:
public class User {
private String name = "defaultName";
private int age = 18;
}
直接用 new User() 创建对象时,这些字段就会有默认值。但当我们使用 @Builder 构建对象时,发现这些默认值“消失”了:
@Builder
public class User {
private String name = "defaultName";
private int age = 18;
}
public class Main {
public static void main(String[] args) {
User user = User.builder().build();
System.out.println(user.getName()); // 输出 null
System.out.println(user.getAge()); // 输出 0
}
}
问题分析:@Builder 和默认值冲突的原因
Lombok 的 @Builder 注解会生成一个独立的 Builder 类。Builder 类中,每个字段都会有自己的存储变量,当你调用 build() 时,会用 Builder 内部存储的值来创建对象。
关键点:
- Builder 内部的字段默认值是 Java 类型默认值,而不是类字段的默认值。
- 所以即使你在类中给字段写了
private String name = "defaultName";,Builder 也不会去读取这个默认值。 - 如果你在 build() 之前没有调用对应的 setter 方法,这个字段就会保持 Builder 内部的默认值(String 为 null,int 为 0)。
解决方案:使用 @Builder.Default
Lombok 提供了 @Builder.Default 注解,专门用来解决这个问题。它会告诉 Builder,在构建对象时如果没有显式设置值,使用字段的初始化值作为默认值。
修改后的示例:
@Builder
public class User {
@Builder.Default
private String name = "defaultName";
@Builder.Default
private int age = 18;
}
public class Main {
public static void main(String[] args) {
User user = User.builder().build();
System.out.println(user.getName()); // 输出 defaultName
System.out.println(user.getAge()); // 输出 18
}
}
工作原理:
@Builder.Default会在 Builder 类中生成一个 默认值初始化逻辑。- 当 build() 被调用时,如果 Builder 中没有设置这个字段,则使用默认值初始化字段。
- 如果 Builder 已经通过链式调用设置了值,则使用用户设置的值。
常见错误与注意事项
- 忘记加 @Builder.Default
@Builder
private String name = "defaultName"; // ❌ 错误
这种写法不会生效,build 后仍然是 null。
- 与 @NonNull 冲突
@Builder
@NonNull
@Builder.Default
private String name = "defaultName"; // ❌ Lombok 会报错
@NonNull 和 @Builder.Default 不要同时使用,因为默认值初始化逻辑可能与非空检查冲突。
- 不要在构造器里重复初始化
如果你同时有全参构造器或者 @AllArgsConstructor 初始化字段,Builder 默认值可能不会生效。建议依赖 @Builder.Default 的初始化逻辑。
总结
- 在类中直接给字段赋值,
new时会生效。 - 使用
@Builder构建对象时,类字段的默认值不会生效。 - 解决方案是为字段添加
@Builder.Default注解。 - 注意与
@NonNull或自定义构造器的冲突。
通过 @Builder.Default,我们就能让 Builder 构建对象时也保留默认值,从而避免 build 出来的对象字段为 null 或 0 的问题。

1421

被折叠的 条评论
为什么被折叠?



