Java lombok 中的默认值。如何使用构造函数和构建器初始化默认值

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/47883931/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 02:42:53  来源:igfitidea点击:

Default value in lombok. How to init default with both constructor and builder

javalombok

提问by Vitalii

I have an object

我有一个对象

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserInfo {
    private int id;
    private String nick;
    private boolean isEmailConfirmed = true;
}

And I initialize it in two ways

我用两种方式初始化它

UserInfo ui = new UserInfo();
UserInfo ui2 = UserInfo.builder().build();

System.out.println("ui: " + ui.isEmailConfirmed());
System.out.println("ui2: " + ui2.isEmailConfirmed());

Here is output

这是输出

ui: true
ui2: false

It seems that builder does not get a default value. I add @Builder.Defaultannotation to my property and my object now looks like this

似乎 builder 没有获得默认值。我@Builder.Default向我的属性添加注释,我的对象现在看起来像这样

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserInfo { 
    private int id;
    private String nick;
    @Builder.Default
    private boolean isEmailConfirmed = true;
}

Here is console output

这是控制台输出

ui: false
ui2: true

How can I make them both be true?

我怎样才能让他们都成为true

采纳答案by Michael A. Schaffrath

My guess is that it's not possible (without having delomboked the code). But why don't you just implement the constructor you need? Lombok is meant to make your life easier, and if something won't work with Lombok, just do it the old fashioned way.

我的猜测是这是不可能的(没有对代码进行 delomboked)。但是你为什么不实现你需要的构造函数呢?Lombok 旨在让您的生活更轻松,如果 Lombok 无法解决某些问题,请按照老式方法进行操作。

@Data
@Builder
@AllArgsConstructor
public class UserInfo { 
    private int id;
    private String nick;
    @Builder.Default
    private boolean isEmailConfirmed = true;

    public UserInfo(){
        isEmailConfirmed = true;
    }
}

Console output:

控制台输出:

ui: true
ui2: true

回答by Sahil Chhabra

Another way is define your own gettermethod overridingthe lombokgetter:

另一种方法是定义你自己的getter方法覆盖龙目岛的getter:

@Data
@Builder
@AllArgsConstructor
public class UserInfo { 
    private int id;
    private String nick;
    private Boolean isEmailConfirmed;

    public Boolean getIsEmailConfirmed(){
      return Objects.isNull(isEmailConfirmed) ? true : isEmailConfirmed;
    }
}

回答by Marcin K?opotek

Since the @Builder.Defaultannotation is broken, I wouldn't use it at all. You can, however, use the following approach by moving the @Builderannotation from class level to the custom constructor:

由于@Builder.Default注释已损坏,我根本不会使用它。但是,您可以通过将@Builder注释从类级别移动到自定义构造函数来使用以下方法:

@Data
@NoArgsConstructor
public class UserInfo {

    private int id;
    private String nick;
    private boolean isEmailConfirmed = true;

    @Builder
    @SuppressWarnings("unused")
    private UserInfo(int id, String nick, Boolean isEmailConfirmed) {
        this.id = id;
        this.nick = nick;
        this.isEmailConfirmed = Optional.ofNullable(isEmailConfirmed).orElse(this.isEmailConfirmed);
    }
}

This way you ensure:

这样您可以确保:

  • the field isEmailConfirmedis initialized only in one place making the code less error-prone and easier to maintain later
  • the UserInfoclass will be initialized the same way either you use a builder or a no-args constructor
  • 该字段isEmailConfirmed仅在一处初始化,从而使代码不易出错且以后更易于维护
  • UserInfo班将被初始化或者您使用的助洗剂或无参数的构造以同样的方式

In other words, the condition holds true:

换句话说,条件成立true

new UserInfo().equals(UserInfo.builder().build())

In that case, the object creation is consistent no matter how you create it. It is especially important when your class is used by a mapping framework or by JPA provider when you are not instantiating it manually by a builder but a no-args constructor is invoked behind your back to create the instance.

在这种情况下,无论您如何创建对象,对象创建都是一致的。当您的类被映射框架或 JPA 提供者使用时,当您不是由构建器手动实例化它,而是在背后调用无参数构造函数来创建实例时,这一点尤其重要。

The approach described aboveis very similar but it has a major drawback. You have to initialize the field in two places which makes the code error-prone as you are required to keep the values consistent.

该方法上面描述的非常相似,但它有一个很大的缺点。您必须在两个地方初始化该字段,这会使代码容易出错,因为您需要保持值一致。

回答by laurent

Here's my approach :

这是我的方法:

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder(toBuilder = true)
public class UserInfo { 
    private int id;
    private String nick;
    private boolean isEmailConfirmed = true;
}

And then

进而

UserInfo ui = new UserInfo().toBuilder().build();

回答by gavenkoa

Custom constructors and @Builder.Defaultprobably will never work together.

自定义构造函数@Builder.Default可能永远不会一起工作。

Framework authors want to avoid double initializations for @Builder.

框架作者希望避免对@Builder.

I reuse .builder()by public static CLAZZ of(...)methods:

.builder()通过public static CLAZZ of(...)方法重用:

@Builder
public class Connection {
    private String user;
    private String pass;

    @Builder.Default
    private long timeout = 10_000;

    @Builder.Default
    private String port = "8080";

    public static Connection of(String user, String pass) {
        return Connection.builder()
            .user(user)
            .pass(pass)
            .build();
    }

    public static Connection of(String user, String pass, String port) {
        return Connection.builder()
            .user(user)
            .pass(pass)
            .port(port)
            .build();
    }

    public static Connection of(String user, String pass, String port, long timeout) {
        return Connection.builder()
            .user(user)
            .pass(pass)
            .port(port)
            .timeout(timeout)
            .build();
    }
}

Check corresponding discussion: https://github.com/rzwitserloot/lombok/issues/1347

查看对应讨论:https: //github.com/rzwitserloot/lombok/issues/1347

回答by LordOfThePigs

My experience is that @Builderworks best when it is the only means of instantiating a class, and therefore works best when paired with @Valuerather than @Data.

我的经验是@Builder效果最好时,它是一个类实例化的唯一途径,因此,当与配对的效果最好@Value,而不是@Data

For classes where all fields are mutable in any order anyway, and for which you want to keep the chained calls, consider replacing it with @Accessors(chain=true)or @Accessors(fluent=true).

对于所有字段都以任何顺序可变的类,并且您希望保留链接调用,请考虑将其替换为@Accessors(chain=true)@Accessors(fluent=true)

@Data
@Accessors(fluent=true)
public class UserInfo {
    private int id;
    private String nick;
    private boolean isEmailConfirmed = true;
}

This allows you to construct your objects fluently in the code, and avoid un-necessary creation of Builder objects:

这使您可以在代码中流畅地构建对象,并避免不必要地创建 Builder 对象:

UserInfo ui = new UserInfo().id(25).nick("John");

回答by ifelse.codes

Initialize the properties in the No-Arg Constructor

初始化 No-Arg 中的属性 Constructor

converted
private boolean isEmailConfirmed = true;

转换
private boolean isEmailConfirmed = true;

to

public class UserInfo {

    public UserInfo() {
        this.isEmailConfirmed = true;
    }

}

回答by Andrey Serebryanskiy

In version 1.18.2 both @NoArgsConstructorand @Builderwork, but not completely.

在 1.18.2 版本中@NoArgsConstructor和 都可以@Builder工作,但不完全。

Constructor with one or more fields will null all other default initialisations: new UserInfo("Some nick")will cause isEmailConfirmedto be false again.

具有一个或多个字段的构造函数将使所有其他默认初始化为空:new UserInfo("Some nick")isEmailConfirmed再次导致为假。

My way to handle this is:

我的处理方法是:

public UserInfo(String nick) {
  this();
  this.nick = nick;
}

This way all default fields will be initialised and we'll get expected constructor.

这样所有默认字段都将被初始化,我们将获得预期的构造函数。

回答by George L

You can create a static Builder class with default values populated:

您可以创建一个静态 Builder 类,并填充默认值:

@Data
@Builder(builderClassName="Builder")
@NoArgsConstructor
@AllArgsConstructor
public class UserInfo {
    private int id;
    private String nick;
    private boolean isEmailConfirmed;
    public static class Builder{
          //Set defaults here
          private boolean isEmailConfirmed = true;
    }
}