Java lombok中的默认值。如何使用构造函数和生成器初始化默认值
我有一个目标Java lombok中的默认值。如何使用构造函数和生成器初始化默认值,java,lombok,Java,Lombok,我有一个目标 @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
@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
我怎样才能使它们都成为
真的?我猜这是不可能的(如果没有删除代码的话)。但是为什么不实现所需的构造函数呢?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
更新
自2021年1月起,至少针对生成的构造函数。请注意,当您混合使用Builder.Default
和显式构造函数时,仍然存在一些问题。另一种方法是定义您自己的getter方法覆盖lombokgetter:
@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
注释从类级别移动到自定义构造函数来使用以下方法:
@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);
}
}
通过这种方式,您可以确保:
- 字段
isemailcomfixed
仅在一个位置初始化,使代码更不容易出错,更易于以后维护
UserInfo
类的初始化方式与使用生成器或无参数构造函数的方式相同
换句话说,该条件保持true
:
new UserInfo().equals(UserInfo.builder().build())
在这种情况下,无论您如何创建对象,对象创建都是一致的。当映射框架或JPA提供者使用您的类时,尤其重要的是当您不是由构建器手动实例化它,而是在背后调用无参数构造函数来创建实例时
这种方法非常相似,但有一个主要缺点。您必须在两个地方初始化字段,这使得代码容易出错,因为您需要保持值一致。以下是我的方法:
@数据
@诺尔格构装师
@AllArgsConstructor
@生成器(toBuilder=true)
公共类用户信息{
私有int-id;
私人字符串尼克;
私有布尔值isEmailConfirmed=true;
}
然后
UserInfo ui=newuserinfo().toBuilder().build();
自定义构造函数和@Builder。默认值可能永远不会一起工作
框架作者希望避免对@Builder
进行双重初始化
我通过(…)
方法的公共静态分类重用.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
是实例化类的唯一方法时效果最好,因此与@Value
而不是@Data
配对时效果最好
对于所有字段都以任意顺序可变的类,并希望保持链式调用,请考虑用<代码> @访问器(链=true)<代码> >或代码> @访问器(FLUENT=TRUE)< /COD> < /P>
@数据
@访问器(fluent=true)
公共类用户信息{
私有int-id;
私人字符串尼克;
私有布尔值isEmailConfirmed=true;
}
这允许您在代码中流畅地构造对象,并避免不必要地创建生成器对象:
UserInfo ui=newuserinfo().id(25).nick(“John”);
初始化无参数构造函数中的属性
已转换
private boolean isemailconfirm=true代码>
到
在1.18.2版中,@noargsconstuctor
和@Builder
都可以工作,但不能完全工作
具有一个或多个字段的构造函数将使所有其他默认初始化为空:new UserInfo(“Some nick”)
将导致isemailconfirm
再次为false
我的处理方法是:
public UserInfo(字符串){
这个();
this.nick=nick;
}
这样,所有默认字段都将被初始化,我们将得到预期的构造函数。您可以创建一个静态生成器类,并填充默认值:
@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
已从v1.16.16中断开=它会将字段初始化为null
,而不考虑在字段级别设置的指定默认初始化值。。。请看,解决方案并不完美,因为您有两次初始化字段。一次在字段声明中,第二次在构造函数中。这使得代码容易出错。我曾经使用这个函数来减少代码的错误倾向,我添加了一个JUnit测试来验证无参数构造函数是否编写良好:assertThat(new UserInfo().equals(UserInfo.builder().build()).descripbedas(“在无参数构造函数中未正确设置标记为@builder.Default的某些属性”).isTrue()由于Lombok有许多怪癖,当你不知道这些怪癖可能带来很多麻烦而不是好处时,你也可以尝试Immutables()或Autovalue()。所有其他工具都有一个很大的缺点:它们生成一个新类。它们的问题肯定较少,因为它们只是使用著名(而且丑陋)的注释处理器API.Lombok必须以不同的方式工作,它确实有一些bug。但是,我从一开始就在使用它,而且我对它非常满意。注释并没有完全损坏,但它在非基本对象方面存在问题。对于任何想知道如何使用它的人来说,默认值适用于Boolean
版本的1.16.22
如果您有@Singular
注释,请查看以下注释:TLDR:将您的@Singular
注释移动到新创建的私有构造函数中。最新版本的Lombok似乎不再破坏它。不鼓励在基于属性的getter中使用逻辑。想象一下您想要的情况增加一个额外的方法
@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;
}
}