为什么 Lombok 的 @Builder 在使用默认构造函数创建对象时删除默认字段值?
Why Lombok's @Builder removes default field value when creating object with default constructor?
考虑以下代码:
@RunWith(JUnit4.class)
public class TestClass {
@Test
public void builderTest() throws Exception {
List<Object> list = new LombokBuilderTest().list;
assertNotNull(list);
}
}
@NoArgsConstructor
@AllArgsConstructor
@Builder
class LombokBuilderTest {
@Builder.Default
List<Object> list = new ArrayList<>();
}
即使 list
属性 有默认值,测试也会失败。如果您评论 @Builder
注释,它会按预期工作。为什么龙目岛以这种方式工作?我希望在使用默认构造函数时将空 ArrayList
分配给 list
属性。
这是一个已知问题 (1, 2)。当您使用 @Builder
注释 class 时,您将使用构建器来实例化 class 是 "expected"。当您使用绕过构建过程的 @NoArgsConstructor
时,问题就来了。
为您的示例生成的代码如下所示:
class LombokBuilderTest {
public static class LombokBuilderTestBuilder {
private List<Object> list;
private boolean list$set;
LombokBuilderTestBuilder() {}
public LombokBuilderTestBuilder list(final List<Object> list) {
this.list = list;
list$set = true;
return this;
}
public LombokBuilderTest build() {
return new LombokBuilderTest((list$set ? list : LombokBuilderTest.$default$list()));
}
@Override
public String toString() {
return (("LombokBuilderTest.LombokBuilderTestBuilder(list=" + this.list) + ")");
}
}
List<Object> list;
private static List<Object> $default$list() {
return new ArrayList<>();
}
public static LombokBuilderTestBuilder builder() {
return new LombokBuilderTestBuilder();
}
public LombokBuilderTest() {}
public LombokBuilderTest(final List<Object> list) {
this.list = list;
}
public static void main(String[] args) {
List<Object> list = new LombokBuilderTest().list;
System.out.println(list);
}
}
如您所见,您的初始化值已从字段声明 移动 到 $default$list
方法,使用 no-agrs 构造函数是唯一的方法 "corrupt"实例化。
如第二个 link 中所述,原因是如果赋值表达式(new ArrayList<>()
在你的情况下)是昂贵的,那么使用构建器会导致表达式被执行两次,这是一个性能问题。解决方法是编写您自己的无参数构造函数并在那里进行字段初始化。
考虑以下代码:
@RunWith(JUnit4.class)
public class TestClass {
@Test
public void builderTest() throws Exception {
List<Object> list = new LombokBuilderTest().list;
assertNotNull(list);
}
}
@NoArgsConstructor
@AllArgsConstructor
@Builder
class LombokBuilderTest {
@Builder.Default
List<Object> list = new ArrayList<>();
}
即使 list
属性 有默认值,测试也会失败。如果您评论 @Builder
注释,它会按预期工作。为什么龙目岛以这种方式工作?我希望在使用默认构造函数时将空 ArrayList
分配给 list
属性。
这是一个已知问题 (1, 2)。当您使用 @Builder
注释 class 时,您将使用构建器来实例化 class 是 "expected"。当您使用绕过构建过程的 @NoArgsConstructor
时,问题就来了。
为您的示例生成的代码如下所示:
class LombokBuilderTest {
public static class LombokBuilderTestBuilder {
private List<Object> list;
private boolean list$set;
LombokBuilderTestBuilder() {}
public LombokBuilderTestBuilder list(final List<Object> list) {
this.list = list;
list$set = true;
return this;
}
public LombokBuilderTest build() {
return new LombokBuilderTest((list$set ? list : LombokBuilderTest.$default$list()));
}
@Override
public String toString() {
return (("LombokBuilderTest.LombokBuilderTestBuilder(list=" + this.list) + ")");
}
}
List<Object> list;
private static List<Object> $default$list() {
return new ArrayList<>();
}
public static LombokBuilderTestBuilder builder() {
return new LombokBuilderTestBuilder();
}
public LombokBuilderTest() {}
public LombokBuilderTest(final List<Object> list) {
this.list = list;
}
public static void main(String[] args) {
List<Object> list = new LombokBuilderTest().list;
System.out.println(list);
}
}
如您所见,您的初始化值已从字段声明 移动 到 $default$list
方法,使用 no-agrs 构造函数是唯一的方法 "corrupt"实例化。
如第二个 link 中所述,原因是如果赋值表达式(new ArrayList<>()
在你的情况下)是昂贵的,那么使用构建器会导致表达式被执行两次,这是一个性能问题。解决方法是编写您自己的无参数构造函数并在那里进行字段初始化。