lombok @Builder

时间:2015-04-27 00:43:52

标签: java lombok

如果我将@Builder添加到课程中。创建构建器方法。

Person.builder().name("john").surname("Smith").build();

我需要特定字段。在这种情况下,名称字段是必需的,但姓氏不是。理想情况下,我想宣布它是这样的。

Person.builder("john").surname("Smith").build()

我无法解决如何做到这一点。我尝试将@Builder添加到构造函数中,但它没有用。

@Builder
public Person(String name) {
    this.name = name;
}

11 个答案:

答案 0 :(得分:55)

您可以使用Lombok注释配置轻松完成

import lombok.Builder;
import lombok.ToString;

@Builder(builderMethodName = "hiddenBuilder")
@ToString
public class Person {

    private String name;
    private String surname;

    public static PersonBuilder builder(String name) {
        return hiddenBuilder().name(name);
    }
}

然后像那样使用它

Person p = Person.builder("Name").surname("Surname").build();
System.out.println(p);

当然@ToString是可选的。

答案 1 :(得分:23)

我建议不要使用这种方法,因为你很难在其他对象上一致地应用它。相反,您只需使用E::x = 11, E::y = 11 x = 10 注释标记字段,Lombok将在构造函数和设置器中为您生成空检查,以便@lombok.NonNull失败,如果未设置这些字段。

使用构建器模式可以非常清楚地识别您要将哪些字段设置为哪些值。对于您的示例中的名称字段,这已经丢失,如果您正在构建具有多个必填字段的对象,则所有其他必填字段将进一步丢失。考虑以下示例,您能通过阅读代码来判断哪个字段是哪个?

Builder.build()

答案 2 :(得分:13)

这是另一种方法:

    public string ExecuteStoredProcedure()
    {
        using (DbConnection cnn = GetNewConnection())
        {
            cnn.Open();
            using (DbCommand cmd = cnn.CreateCommand())
            {
                cmd.CommandText = "ucb_sync.get_protein_details";
                cmd.CommandType = CommandType.StoredProcedure;

                DbParameter dbp = cmd.CreateParameter();
                dbp.ParameterName = "protein_batch_id";
                dbp.Value = "PB0000007";
                dbp.DbType = DbType.String;
                cmd.Parameters.Add(dbp);

                DbParameter returnDbp = cmd.CreateParameter();
                returnDbp.Direction = ParameterDirection.ReturnValue;
                returnDbp.ParameterName ="result_data";
                returnDbp.DbType = DbType.String;
                cmd.Parameters.Add(returnDbp);
                try
                {
                    cmd.ExecuteNonQuery();
                }
                catch (Exception e)
                {
                    throw e;
                }
                return returnDbp.Value.ToString();

            }
        }
    }

答案 3 :(得分:9)

让Kevin Day的answer更进一步:

@Builder
@Getter
@AllArgsConstructor(access = AccessLevel.PRIVATE) // If immutability is desired
@ToString
public class Person {
    @NonNull // Presumably name cannot be null since its required by the builder
    private final String name;
    private final String surname;

    private static PersonBuilder builder() {
        return new PersonBuilder();
    }

    public static PersonBuilder builder(String name){
        return builder().name(name);
    }

}

它并不理想,但它提供了编译时强制执行,此类的调用者将只使用一种构建器方法。

答案 4 :(得分:5)

这是我解决问题的方法

File

受这篇博文的启发:

https://blog.jayway.com/2012/02/07/builder-pattern-with-a-twist/

答案 5 :(得分:2)

最简单的解决方案是向所有必填值添加@lombok.NonNull。当未设置必填字段时,Builder将无法构建对象。

这是一个JUnit测试,用于演示final@NonNull的所有组合的行为:

import static org.junit.Assert.fail;

import org.junit.Test;

import lombok.Builder;
import lombok.ToString;

public class BuilderTests {
    @Test
    public void allGiven() {
        System.err.println(Foo.builder().nonFinalNull("has_value").nonFinalNonNull("has_value").finalNull("has_value")
                .finalNonNull("has_value").build());
    }

    @Test
    public void noneGiven() {
        try {
            System.err.println(Foo.builder().build().toString());
            fail();
        } catch (NullPointerException e) {
            // expected
        }
    }

    @Test
    public void nonFinalNullOmitted() {
        System.err.println(
                Foo.builder().nonFinalNonNull("has_value").finalNull("has_value").finalNonNull("has_value").build());
    }

    @Test
    public void nonFinalNonNullOmitted() {
        try {
            System.err.println(
                    Foo.builder().nonFinalNull("has_value").finalNull("has_value").finalNonNull("has_value").build());
            fail();
        } catch (NullPointerException e) {
            // expected
        }
    }

    @Test
    public void finalNullOmitted() {
        System.err.println(
                Foo.builder().nonFinalNull("has_value").nonFinalNonNull("has_value").finalNonNull("has_value").build());
    }

    @Test
    public void finalNonNullOmitted() {
        try {
            System.err.println(Foo.builder().nonFinalNull("has_value").nonFinalNonNull("has_value")
                    .finalNull("has_value").build());
            fail();
        } catch (NullPointerException e) {
            // expected
        }
    }

    @Builder
    @ToString
    private static class Foo {
        private String nonFinalNull;

        @lombok.NonNull
        private String nonFinalNonNull;

        private final String finalNull;

        @lombok.NonNull
        private final String finalNonNull;
    }
}

答案 6 :(得分:1)

结合@Pawel的答案和Max的评论...

Lines <- "React1 | React2 | React3 |  Prod1  | Prod2 | Prod3 |    k

 $OH    | $OH    | NA     | H2O2    | NA    | NA    | 5.50E+09
 $OH    | $HO2   | NA     | H2O     | O2    | NA    | 7.10E+09
 $OH    | $O2    | NA     | OH      | O2    | NA    | 1.00E+10
 H2O2   | $OH    | NA     | $HO2    | H2O   | NA    | 2.70E+07
 $OH    | HCO3   | NA     | $CO3    | NA    | NA    | 8.50E+06
 $OH    | CO2    | NA     | $CO3    | NA    | NA    | 1.00E+06
 $OH    | CO3    | NA     | $CO3    | OH    | NA    | 3.90E+08
 $OH    | $CO3   | NA     | unknown | NA    | NA    | 3.00E+09
 Cl     | $OH    | NA     | $ClOH   | NA    | NA    | 4.30E+09
 $Cl2   | $OH    | NA     | HOCl    | Cl    | NA    | 1.00E+09
 HOCl   | $OH    | NA     | $ClO    | H2O   | NA    | 2.00E+09
 ClO    | $OH    | NA     | $ClO    | OH    | NA    | 8.80E+00"
DF <- read.table(text = Lines, header = TRUE, sep = "|", strip.white = TRUE,
 as.is = TRUE)

答案 7 :(得分:1)

最佳实践:

import lombok.Builder;
import lombok.NonNull;

@Builder(builderMethodName = "privateBuilder")
public class Person {
    @NonNull
    private String name;
    private String surname;

    public static class PersonNameBuilder {
        public PersonBuilder name(String name) {
            return Person.privateBuilder().name(status);
        }
    }

    public static PersonNameBuilder builder(String name) {
        return new PersonNameBuilder();
    }

    private static PersonBuilder privateBuilder(){
        return new PersonBuilder();
    }
}

用法:

PersonNameBuilder nameBuilder = Person.builder();
PersonBuilder builder = nameBuilder.name("John");
Person p1 = builder.surname("Smith").build();

// Or
Person p2 = Person.builder().name("John").surname("Smith").build();

答案 8 :(得分:0)

如果需要此功能,则可以自己定制构建器类,并且仍然可以添加@Builder注释。

@Builder
public class Person {

    public static class PersonBuilder {
        private String name;

        private PersonBuilder() {
        }

        public PersonBuilder(final String name) {
            this.name = name;
        }
    }

    private static PersonBuilder builder() {
        return null; // or we can throw exception.
    }

    public static PersonBuilder builder(final String name) {
        return new PersonBuilder(clientId);
    }
}

答案 9 :(得分:0)

User类为例,id字段为必填字段:

@AllArgsConstructor(access = AccessLevel.PRIVATE) // required, see https://stackoverflow.com/questions/51122400/why-is-lombok-builder-not-compatible-with-this-constructor
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@Builder
@Getter
public class User {
    private String id;
    private String name;
    private int age;

    public static UserBuilder builder(final String id) {
        return new UserBuilder().id(id);
    }
}

您只能由User之类的构建器 初始化User user = User.builder("id-123").name("Tom").build;实例。使用私有的无参数构造函数,您将无法User user = new User();User user = new User("id-123");,因此您始终需要传递必需的参数id。请注意,初始化后的实例是不可变的。

答案 10 :(得分:0)

尽管我很想拥有编译时验证功能,但库的作者已经明确表示 the feature probably won't be added.

所以我对此的看法是,拥有这样的东西。

@Builder
public class Person {
  String name;
  Integer age;
  Optional optional;

  @Builder
  public class Optional {
    String surname;
    String companyName;
    String spouseName;
}

}

你可以像这样使用它

 Person p = Person.builder()
            .age(40)
            .name("David")
            .optional(Person.Optional.builder()
                    .surname("Lee")
                    .companyName("Super Company")
                    .spouseName("Emma")
                    .build())
            .build();

不,没有验证。 但从图书馆用户的角度来看, 很清楚什么是必需的,什么不是,并且无需查看文档即可构建对象实例。