如果我将@Builder添加到课程中。创建构建器方法。
Person.builder().name("john").surname("Smith").build();
我需要特定字段。在这种情况下,名称字段是必需的,但姓氏不是。理想情况下,我想宣布它是这样的。
Person.builder("john").surname("Smith").build()
我无法解决如何做到这一点。我尝试将@Builder添加到构造函数中,但它没有用。
@Builder
public Person(String name) {
this.name = name;
}
答案 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)
答案 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();
不,没有验证。 但从图书馆用户的角度来看, 很清楚什么是必需的,什么不是,并且无需查看文档即可构建对象实例。