使用Lombok为具有必需和可选属性的类创建构建器

时间:2019-01-11 23:23:24

标签: java builder lombok

搜索插件以避免样板代码实现Joshua Blochbuilder pattern,我发现了令人惊叹的Lombok Project,它使您能够通过如下注释生成生成器:

onClick

如您所见,没有样板代码,您可以通过调用提供的静态@Builder public class Person { private String name; private String address; private String secondAddress; } PersonBuilder.builder().name("yourName").address("your Address").build(); 方法轻松地创建Person的实例,将类似于setter的调用链接起来就可以使用JavaBeans-Pattern并通过调用builder();

结束链

与构建器模式相比,JavaBeans-Pattern的缺点之一是(来自Effective Java):

  

由于构造被划分为多个调用,因此 JavaBean在构造期间可能处于不一致状态

假设在上面的示例中,前两个属性(名称和地址)对于构造Person实例是必不可少的,则Lombok实现构建器模式的方式使开发人员能够拆分/缩短构造并可能build()的实例不一致,例如:

Person

Joshua Bloch的解决方案更喜欢使用强制属性作为参数的构建器方法,这样就不可能将构造分为多个调用,如Item 2: Consider a builder when faced with many constructor parameters所示。

我的问题是: 是否有任何方便的方法,例如@Builder的注释参数或属性级别的Springs @Required或@Mandatory之类的方法,以强制Lombok避免像Joshua Bloch所建议的那样提供无参数的生成器构造函数并向构造函数提供强制性参数? >

我尝试了@Builder documentation中的许多选项,但找不到理想的解决方案。

对我有用的内容描述如下:

  • 使用必填参数为Person定义构造函数,
  • 使用用于强制性参数的参数化签名覆盖构建器构造函数。

有点重复,可以避免。请参阅我的解决方案在约书亚·布洛赫(Joshua Bloch)的例子中的应用。

Person p = PersonBuilder.builder().name("yourName").build();
...
System.out.println(p.getAddress());
...
p.setAddress("your address");

2 个答案:

答案 0 :(得分:4)

根据@Builder docs,此注释可以与@NonNull一起使用。如果标记为@NonNull的字段为null,您将得到NullPointerException阻止创建无效对象:

@Builder
static class Person {
  @NonNull
  private final String name;
  @NonNull
  private final Integer age;
}

public static void main(String[] args) {
  Person.builder()
        .name("Fred")
        .build(); // java.lang.NullPointerException: age is marked @NonNull but is null
}

要走得更远,您可以自己定义builder方法。如果存在该方法,则Lombok不会生成它,您现在可以强制参数编译时间。

@Builder
static class Person {
  @NonNull
  private final String name;
  @NonNull
  private final Integer age;

  public static PersonBuilder builder(String name, Integer age) {
    return new PersonBuilder().name(name).age(age);
  }
}

public static void main(String[] args) {
  Person.builder("Fred", 11)
        .build();
}

由于构建器类仍可访问,因此仍然可以通过编写new Person.PersonBuilder()来创建构建器。

答案 1 :(得分:0)

此外,可以使用扩展名:

@Builder.Default <modifier><instanceVariable>=<default-value>

like:@Builder.Default private String myVariable = ""

请阅读:@Builder default properties

避免在某些情况下(如持久性,索引编制等)(在设置id或属性减少时,通过update / deleteBy / findBy进行设置,而没有完整的对象图),而不会要求某些属性设置的编译器错误。

这是一个优雅的解决方案,它不按建议覆盖 .build()设置者