簡體   English   中英

lombok 中的默認值。 如何使用構造函數和構建器初始化默認值

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

我有一個對象

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

我用兩種方式初始化它

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

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

這是輸出

ui: true
ui2: false

似乎 builder 沒有獲得默認值。 我將@Builder.Default注釋添加到我的屬性中,我的對象現在看起來像這樣

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

這是控制台輸出

ui: false
ui2: true

我怎樣才能讓它們都是true

我的猜測是這是不可能的(沒有對代碼進行 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;
    }
}

控制台輸出:

ui: true
ui2: true

更新
截至 01/2021,此錯誤似乎已在 Lombok 中修復,至少對於生成的構造函數而言。 請注意,當您混合使用Builder.Default和顯式構造函數時,仍然存在類似的問題

由於@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);
    }
}

這樣您可以確保:

  • 字段isEmailConfirmed僅在一處初始化,從而使代碼不易出錯isEmailConfirmed易於以后維護
  • UserInfo類將以與使用構建器或無參數構造函數相同的方式初始化

換句話說,該條件成立true

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

在這種情況下,無論您如何創建對象,對象創建都是一致的。 當您的類被映射框架或 JPA 提供者使用時,當您不是由構建器手動實例化它,而是在背后調用無參數構造函數來創建實例時,這一點尤其重要。

該方法上面描述的非常相似,但它有一個很大的缺點。 您必須在兩個地方初始化該字段,這會使代碼容易出錯,因為您需要保持值一致。

另一種方法是定義自己的getter方法來覆蓋lombok 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;
    }
}

我的經驗是@Builder在它是實例化類的唯一方法時效果最好,因此在與@Value而不是@Data配對時效果最好。

對於所有字段以任何順序可變的類,並且您希望保留鏈接調用,請考慮將其替換為@Accessors(chain=true)@Accessors(fluent=true)

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

這允許您在代碼中流暢地構建對象,並避免不必要地創建 Builder 對象:

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

這是我的方法:

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

接着

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

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

具有一個或多個字段的構造函數將使所有其他默認初始化為空: new UserInfo("Some nick")將導致isEmailConfirmed再次為 false。

我的處理方法是:

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

這樣所有默認字段都將被初始化,我們將獲得預期的構造函數。

初始化 No-Arg Constructor的屬性

轉換
private boolean isEmailConfirmed = true;

public class UserInfo {

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

}

您可以創建一個靜態 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;
    }
}

自定義構造函數和@Builder.Default可能永遠不會一起工作。

框架作者希望避免對@Builder進行雙重初始化。

我通過public static CLAZZ of(...)方法重用.builder()

@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();
    }
}

查看對應討論: https : //github.com/rzwitserloot/lombok/issues/1347

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM