龙目岛的默认值。如何使用构造函数和构建器初始化默认值
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.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
?
我的猜测是这是不可能的(如果没有删除代码)。但是你为什么不直接实现你需要的构造函数呢? 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 起,this bug seems to be fixed in Lombok, at least for generated constructors. Note that there is still a similar issue 当您混合使用 Builder.Default
和显式构造函数时。
另一种方法是定义您自己的 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.Default
annotation is broken之后,我就再也不用它了。但是,您可以通过将 @Builder
注释从 class 级别移动到自定义构造函数来使用以下方法:
@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
仅在一个地方初始化,使代码不易出错且以后更易于维护
UserInfo
class 的初始化方式与使用构建器或无参数构造函数的方式相同
也就是说,条件成立true
:
new UserInfo().equals(UserInfo.builder().build())
那样的话,不管你怎么创建,对象的创建都是一致的。当您的 class 被映射框架或 JPA 提供程序使用时,当您没有由构建器手动实例化它,而是在您背后调用无参数构造函数来创建实例时,这一点尤其重要。
方法非常相似,但它有一个主要缺点。您必须在两个地方初始化该字段,这使得代码容易出错,因为您需要保持值一致。
这是我的方法:
@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();
自定义构造函数和 @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();
}
}
我的经验是 @Builder
在它是实例化 class 的唯一方法时效果最好,因此与 @Value
而不是 @Data
配对时效果最好.
对于 classes,其中所有字段无论如何都可以按任何顺序可变,并且您希望为其保留链式调用,请考虑将其替换为 @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");
初始化 No-Arg 中的属性 Constructor
已转换
private boolean isEmailConfirmed = true;
至
public class UserInfo {
public UserInfo() {
this.isEmailConfirmed = true;
}
}
在版本 1.18.2 中,@NoArgsConstructor
和 @Builder
都可以,但不完全。
具有一个或多个字段的构造函数将使所有其他默认初始化为空:new UserInfo("Some nick")
将导致 isEmailConfirmed
再次为假。
我的处理方式是:
public UserInfo(String nick) {
this();
this.nick = nick;
}
这样所有默认字段都将被初始化,我们将获得预期的构造函数。
您可以创建静态生成器 class 并填充默认值:
@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;
}
}
我有对象
@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.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
?
我的猜测是这是不可能的(如果没有删除代码)。但是你为什么不直接实现你需要的构造函数呢? 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 起,this bug seems to be fixed in Lombok, at least for generated constructors. Note that there is still a similar issue 当您混合使用 Builder.Default
和显式构造函数时。
另一种方法是定义您自己的 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.Default
annotation is broken之后,我就再也不用它了。但是,您可以通过将 @Builder
注释从 class 级别移动到自定义构造函数来使用以下方法:
@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
仅在一个地方初始化,使代码不易出错且以后更易于维护 UserInfo
class 的初始化方式与使用构建器或无参数构造函数的方式相同
也就是说,条件成立true
:
new UserInfo().equals(UserInfo.builder().build())
那样的话,不管你怎么创建,对象的创建都是一致的。当您的 class 被映射框架或 JPA 提供程序使用时,当您没有由构建器手动实例化它,而是在您背后调用无参数构造函数来创建实例时,这一点尤其重要。
方法
这是我的方法:
@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();
自定义构造函数和 @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();
}
}
我的经验是 @Builder
在它是实例化 class 的唯一方法时效果最好,因此与 @Value
而不是 @Data
配对时效果最好.
对于 classes,其中所有字段无论如何都可以按任何顺序可变,并且您希望为其保留链式调用,请考虑将其替换为 @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");
初始化 No-Arg 中的属性 Constructor
已转换
private boolean isEmailConfirmed = true;
至
public class UserInfo {
public UserInfo() {
this.isEmailConfirmed = true;
}
}
在版本 1.18.2 中,@NoArgsConstructor
和 @Builder
都可以,但不完全。
具有一个或多个字段的构造函数将使所有其他默认初始化为空:new UserInfo("Some nick")
将导致 isEmailConfirmed
再次为假。
我的处理方式是:
public UserInfo(String nick) {
this();
this.nick = nick;
}
这样所有默认字段都将被初始化,我们将获得预期的构造函数。
您可以创建静态生成器 class 并填充默认值:
@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;
}
}