[英]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.