lombok中的默认值.如何使用构造函数和构建器初始化

Vit*_*lii 38 java lombok

我有一个对象

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserInfo {
    private int id;
    private String nick;
    private boolean isEmailConfirmed = true;
}
Run Code Online (Sandbox Code Playgroud)

我用两种方式初始化它

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

System.out.println("ui: " + ui.isEmailConfirmed());
System.out.println("ui2: " + ui2.isEmailConfirmed());
Run Code Online (Sandbox Code Playgroud)

这是输出

ui: true
ui2: false
Run Code Online (Sandbox Code Playgroud)

似乎构建器没有获得默认值.我@Builder.Default向我的属性添加注释,我的对象现在看起来像这样

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserInfo { 
    private int id;
    private String nick;
    @Builder.Default
    private boolean isEmailConfirmed = true;
}
Run Code Online (Sandbox Code Playgroud)

这是控制台输出

ui: false
ui2: true
Run Code Online (Sandbox Code Playgroud)

我怎么能让它们都成为true

Mar*_*tek 34

由于@Builder.Default注释被打破,我根本不会使用它.但是,您可以使用以下方法:

@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);
    }
}
Run Code Online (Sandbox Code Playgroud)

这样你可以确保:

  • 该字段@Builder仅在一个地方初始化,使代码不易出错,以后更容易维护
  • isEmailConfirmed班将被初始化或者您使用的助洗剂或无参数的构造以同样的方式

换句话说,条件成立UserInfo:

new UserInfo().equals(UserInfo.builder().build())
Run Code Online (Sandbox Code Playgroud)

在这种情况下,无论您如何创建对象,对象创建都是一致的.当您没有由构建器手动实例化它而您的类由映射框架或JPA提供程序使用时,尤其重要的是,在您的后面调用no-args构造函数来创建实例.

该方法上面描述的非常相似,但它有一个很大的缺点.您必须在两个位置初始化字段,这会使代码容易出错,因为您需要保持值一致.

  • 所有其他工具都有一个很大的缺点:它们生成一个新类。它们的问题肯定更少,因为它们只是使用众所周知的(而且丑陋的)API 的注释处理器。Lombok 必须以不同的方式工作,并且它确实有一些错误。然而,我从一开始就在使用它,而且我对它非常满意。 (3认同)
  • 由于 Lombok 有很多怪癖,当您不知道这些怪癖时,可能会带来很多麻烦而不是好处,您也可以尝试 Immutables (https://immutables.github.io) 或 Autovalue (https://github.com/google/自动/blob/master/value/userguide/builders.md)。 (2认同)

Mic*_*ath 18

我的猜测是,这是不可能的(没有删除代码).但是你为什么不实现你需要的构造函数呢?龙目岛旨在让您的生活更轻松,如果某些东西不能与龙目岛一起使用,那就按老式方式做吧.

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

    public UserInfo(){
        isEmailConfirmed = true;
    }
}
Run Code Online (Sandbox Code Playgroud)

控制台输出:

ui: true
ui2: true
Run Code Online (Sandbox Code Playgroud)

  • 警告!目前这个`@Builder.Default`已从v1.16.16中删除=无论在字段级别设置的指定默认初始化值如何,它都会将您的字段初始化为"null"...请参阅[此处的问题](https:// github .COM/rzwitserloot /龙目岛/问题/ 1347) (4认同)

Sah*_*bra 8

另一种方法是定义你自己的getter方法覆盖龙目岛的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;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 不鼓励在基于属性的 getter 中使用逻辑。想象一下你想在类中添加一个额外方法的情况,该方法依赖于字段(isEmailConfirmed)。实现者可能会混淆直接使用字段或调用 getter。值可能不同,这可能会导致错误。 (8认同)
  • @SahilChhabra 歧义是不好的。除非您想让代码的用户进一步感到困惑,否则 Deprecated 有特殊用途。最后*假设*它的“你的类”和“你应该知道”这个字段不被使用等等。等等还有另一个严重的问题..坚持一致性,你的代码将对未来的开发人员及其最终表现出关心用户! (2认同)
  • @prash我同意他的答案更好。我只是给出了另一种方法。我同意它存在您提到的问题,但这取决于用例。另外,我从未说过任何反对最佳实践的话。我只是说有时你无法遵循每一个最佳实践(再次取决于用例)。 (2认同)

Lor*_*igs 5

我的经验是,@Builder当它是实例化类的唯一方法时,效果最好,因此与 配对而@Value不是 时效果最好@Data

对于所有字段都以任何顺序可变的类,并且您想要保留链式调用,请考虑将其替换为@Accessors(chain=true)or @Accessors(fluent=true)

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

这使您可以在代码中流畅地构造对象,并避免不必要的创建 Builder 对象:

UserInfo ui = new UserInfo().id(25).nick("John");
Run Code Online (Sandbox Code Playgroud)