Java | Lombok @Builder.Default 排障指南:为什么 build 时默认值丢失?
关注: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()); // 输出 nullSystem.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.Defaultprivate String name = "defaultName";@Builder.Defaultprivate int age = 18;
}public class Main {public static void main(String[] args) {User user = User.builder().build();System.out.println(user.getName()); // 输出 defaultNameSystem.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 的问题。