2017-08-31 242 views
1

考虑下面的代码:为什么Lombok的@Builder在使用默认构造函数创建对象时删除默认字段值?

@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属性。

+0

不应该是'LombokBuilderTest.builder()。build().list'? – chrylis

回答

1

这是一个已知问题(12)。当你用@Builder注解一个类时,你会“期望”使用构建器来实例化类。当您使用绕过构建过程的@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方法移动和使用无AGRS构造函数这是“腐败”实例化的唯一方法。

正如第二个链接中所解释的,原因是如果赋值表达式(您的案例中的new ArrayList<>())代价高昂,那么使用构建器会导致表达式执行两次,这是性能问题。解决方法是编写自己的无参数构造函数并在那里进行字段初始化。

相关问题