Java 带有 Lombok @Builder 的必需参数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29885428/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Required arguments with a Lombok @Builder
提问by jax
If I add @Builderto a class. The builder method is created.
如果我将@Builder添加到一个类中。构建器方法已创建。
Person.builder().name("john").surname("Smith").build();
I have a requirement where a particular field is required. In this case, the name field is required but the surname is not. Ideally, I would like to declare it like so.
我有一个需要特定字段的要求。在这种情况下,姓名字段是必需的,但姓氏不是。理想情况下,我想这样声明。
Person.builder("john").surname("Smith").build()
I can't work out how to do this. I have tried adding the @Builder to a constructor but it didn't work.
我不知道如何做到这一点。我曾尝试将 @Builder 添加到构造函数中,但没有奏效。
@Builder
public Person(String name) {
this.name = name;
}
采纳答案by Pawel
You can do it easily with Lombok annotation configuration
您可以使用 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);
}
}
And then use it like that
然后像这样使用它
Person p = Person.builder("Name").surname("Surname").build();
System.out.println(p);
Of course @ToString
is optional here.
当然@ToString
这里是可选的。
回答by Kevin Day
Here's another approach:
这是另一种方法:
@Builder()
@Getter
@ToString
public class Person {
private final String name;
private final String surname;
public static PersonBuilder builder(String name){
return new PersonBuilder().name(name);
}
public static void main(String[] args) {
Person p = Person.builder("John Doe")
.surname("Bill")
.build();
}
}
回答by Anton Koscejev
I would recommend against this approach, as you will struggle to apply it consistently on other objects. Instead, you can just mark fields with @lombok.NonNull
annotation and Lombok will generate null checks for you in the constructor and setters, so that Builder.build()
will fail, if those fields are not set.
我建议不要使用这种方法,因为您将很难在其他对象上始终如一地应用它。相反,您只需使用@lombok.NonNull
注释标记字段,Lombok 将在构造函数和设置器中为您生成空检查,因此Builder.build()
如果未设置这些字段,则会失败。
Using builder pattern allows you to have very clear identification of which fields you're setting to which values. This is already lost for name field in your example, and it will further be lost for all other required fields, if you're building an object with multiple required fields. Consider the following example, can you tell which field is which just by reading code?
使用构建器模式可以让您非常清楚地识别您将哪些字段设置为哪些值。在您的示例中, name 字段已经丢失了,如果您正在构建具有多个必填字段的对象,所有其他必填字段将进一步丢失。考虑下面的例子,你能通过阅读代码知道哪个字段是哪个吗?
Person.builder("John", "Michael", 16, 1987) // which is name, which is surname? what is 16?
.year(1982) // if this is year of birth, then what is 1987 above?
.build()
回答by kozla13
This is my solution for the problem
这是我对问题的解决方案
import lombok.Builder;
import lombok.Data;
import lombok.NonNull;
@Data
@Builder(builderMethodName = "privateBuilder")
public class Person {
@NonNull
private String name;
@NonNull
private String surname;
private int age;//optional
public static Url safeBuilder() {
return new Builder();
}
interface Url {
Surname name(String name);
}
interface Surname {
Build surname(String surname);
}
interface Build {
Build age(int age);
Person build();
}
public static class Builder implements Url, Surname, Build {
PersonBuilder pb = Person.privateBuilder();
@Override
public Surname name(String name) {
pb.name(name);
return this;
}
@Override
public Build surname(String surname) {
pb.surname(surname);
return this;
}
@Override
public Build age(int age) {
pb.age(age);
return this;
}
@Override
public Person build() {
return pb.build();
}
}
}
inspired by this blog post:
灵感来自这篇博文:
https://blog.jayway.com/2012/02/07/builder-pattern-with-a-twist/
https://blog.jayway.com/2012/02/07/builder-pattern-with-a-twist/
回答by lilalinux
The simpliest solution is to add a @lombok.NonNull
to all mandatory values. The Builder will fail to build the object when mandatory fields are not set.
最简单的解决方案是将 a 添加@lombok.NonNull
到所有必需值。如果未设置必填字段,Builder 将无法构建对象。
Here's a JUnit test to demonstrate the behavior of all combinations of final
and @NonNull
:
这里有一个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;
}
}
回答by The Gilbert Arenas Dagger
Taking Kevin Day's answera step further:
将凯文·戴 (Kevin Day) 的回答更进一步:
@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);
}
}
It's not ideal, but it provides compile time enforcement and callers of this class will have exactly one builder method to use.
这并不理想,但它提供了编译时强制执行,并且此类的调用者将只使用一个构建器方法。
回答by Krishna M
If you need this functionality, you can customize the builder class by yourself and you can still add @Builder
Annotation.
如果你需要这个功能,你可以自己自定义builder类,你仍然可以添加@Builder
Annotation。
@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);
}
}
回答by coderz
Take User
class as example, id
field is required:
以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);
}
}
You can onlyinitialize a User
instance by builder like User user = User.builder("id-123").name("Tom").build;
. With private no args constructer, you are not able to User user = new User();
or User user = new User("id-123");
so you always need to pass the required parameter id
. Please note the initialized instance is immutable.
你可以只初始化一个User
由像建设者实例User user = User.builder("id-123").name("Tom").build;
。使用 private no args 构造函数,你不能User user = new User();
或者User user = new User("id-123");
所以你总是需要传递所需的参数id
。请注意初始化的实例是不可变的。
回答by codemano
Combining the answer from @Pawel and comment from Max ...
结合@Pawel 的回答和 Max 的评论......
import lombok.Builder;
import lombok.ToString;
@Builder
public class Person {
private String name;
private String surname;
public static PersonBuilder builder(String name) {
return new PersonBuilder().name(name);
}
}