使用Lombok 1.18.24能否同时生成必填参数构造器与Builder?
可以实现需求,以下是两种可行方案:
方案一:手动组合注解替代@Value
避免@Value自动生成私有全参构造器导致的Builder冲突,手动组合@Value的等效注解,配合@RequiredArgsConstructor生成目标构造器:
import lombok.AccessLevel; import lombok.Builder; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.ToString; import lombok.experimental.FieldDefaults; @Getter @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) @ToString @EqualsAndHashCode @RequiredArgsConstructor // 生成仅接收alpha的构造器 @Builder class Foo { String alpha; @Builder.Default String bravo = "x"; static void bar() { // 使用目标构造器 Foo foo1 = new Foo("y"); // 使用Builder(bravo默认值为"x") Foo foo2 = Foo.builder().alpha("y").build(); // 使用Builder自定义bravo Foo foo3 = Foo.builder().alpha("y").bravo("z").build(); } }
说明:
@FieldDefaults实现@Value的「字段私有+不可变」特性;@RequiredArgsConstructor会自动识别未初始化的final字段(仅alpha),生成对应构造器;@Builder结合@Builder.Default生成支持默认值的Builder,内部会自动生成全参构造器用于实例化,与目标构造器共存不冲突。
方案二:基于@Value手动补充构造器
如果必须使用@Value,可以手动覆盖其生成的私有全参构造器,同时添加目标单参构造器:
import lombok.Builder; import lombok.Value; @Value @Builder class Foo { String alpha; @Builder.Default String bravo = "x"; // 手动定义public全参构造器,供Builder调用 public Foo(String alpha, String bravo) { this.alpha = alpha; this.bravo = bravo; } // 生成仅接收alpha的构造器,复用全参构造器传入默认值 public Foo(String alpha) { this(alpha, "x"); } static void bar() { new Foo("y"); // 调用目标构造器 Foo.builder().alpha("y").build(); // Builder使用全参构造器,自动传入bravo默认值 } }
说明:
@Value原本会生成私有全参构造器,手动定义public全参构造器后,Builder可以正常访问并使用它;- 单参构造器通过调用全参构造器传入默认值,保证final字段
bravo被正确初始化,避免编译错误。
你之前报错的原因分析
第一种方案(仅@Value+@Builder+手动构造器):
@Value生成的全参构造器是私有,Builder无法访问,只能尝试调用你手动写的单参构造器,但Builder需要传入两个参数(alpha+bravo),导致参数长度不匹配报错。同时你手动构造器未显式初始化final字段bravo,违反Java语法规范。第二种方案(加@AllArgsConstructor):
@AllArgsConstructor生成的全参构造器会覆盖@Value的私有构造器,但你手动写的单参构造器未初始化bravo,final字段必须被初始化,因此编译报错。第三种方案(加@RequiredArgsConstructor):
在Lombok 1.18.24中,@Builder.Default不会被@RequiredArgsConstructor识别为「已初始化字段」,因此生成的构造器仍包含bravo参数,导致你调用new Foo("y")时参数数量不匹配。第四种方案(同时加两个构造器注解):
@AllArgsConstructor和@RequiredArgsConstructor生成了签名完全相同的构造器(都包含alpha和bravo),导致重复定义报错。
内容的提问来源于stack exchange,提问作者Hollis Waite

