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