【问题标题】:Will @NonNull give an error on using @NoArgsConstructor?@NonNull 在使用 @NoArgsConstructor 时会出错吗?
【发布时间】:2021-07-27 12:53:39
【问题描述】:
@Getter
@Setter
@NoArgsConstructor
public class Company {

    @NonNull
    private String location;
    
    @NonNull
    private String name;
}

现在如果我写类似 -

  1. Company company = new Company();
  2. company.setLocation("Florida");
  3. company.setName("ABC");

问题 1 - 在第 1 行我会收到一个错误,因为创建了一个新对象但位置和名称为空,并且它们用 @NonNull 注释?

问题 2 - 我会在第 2 行和第 3 行得到任何错误吗?

【问题讨论】:

  • 你不能简单地尝试看看会发生什么吗?
  • 哪个@NonNull 注释,因为这对可能发生的事情非常重要。
  • 我的 IDE 遇到了一些问题。还想了解@NonNull 的工作背景。这就是我问的原因
  • @M.Deinum 其中之一?
  • 那么答案是否定的,因为您没有将null 分配给这些字段。如果您执行setName(null),它将引发异常。正如lombok documentation 所解释的那样

标签: java lombok


【解决方案1】:

这很复杂,因为 java 社区以不同的方式处理 null,而“非 null”意味着不同的东西:例如,在 DB 模型类中,它可能意味着:如果您使用 DB 框架生成的 CREATE TABLE 语句要求它为您制作表应该在 SQL 中添加一个 NOT NULL 约束。但是,由于 POJO 也应该能够表示半构建的行(例如,表示数据库中的 unid 列的 unid 字段包含null,因为重点是让数据库使用它的自动序列来填充它,直到你save()它才会发生,因此java端该字段可以并且通常是 null!

因此,lombok 的 NonNull 支持有 4 个方面非常不同:

@RequiredArgsConstructor 和 @AllArgsConstructor,以及暗示其中之一的所有 lombok 功能(@Builder、@Data 和 @Value)。

Lombok 处理 final 或 具有某种 NonNull 注释的任何字段,它明确识别为暗示在该字段为空的情况下甚至不应该存在任何对象(尤其是不包括 JPA 的 NotNull!),并且可以在 lombok.config 中进行配置,但 lombok 附带了一组已知的开箱即用的注释,作为“必需”。

“必填”字段具有以下属性:

  1. @RequiredArgsConstructor 会为它做一个参数。
  2. @RequiredArgsConstructor 和@AllArgsConstructor 创建的构造函数将使用在 lombok.config 中配置的 nullcheck 机制对这些字段进行 null 检查。默认为:if (x == null) throw new NullPointerException("x");。

@NoArgsConstructor

这个是不同的。 NoArgsConstructor 不添加空检查。这完全没有意义:如果 lombok 应该添加它们,那么这意味着唯一正确的答案是 lombok 为您制作了这个构造函数:

public YourType() {
    throw new NullPointerException("NameOfFirstFieldMarkedNonNull");
}

这似乎是一个毫无意义的练习。

因此,相反,lombok 将这些字段保留为空,并假设您知道自己在做什么。通常,您创建这些构造函数要么是因为框架要求您这样做,要么是因为框架将通过立即调用一组 setter 或反射性地更新这些字段来“修复”标记为 never null 的字段包含 null 值的问题。

@Setter 以及暗示它的 lombok 功能 (@Data)。

这些将以相同的方式对参数进行空检查。

@lombok.NonNull 一个参数

与前面的内容不同,此功能仅适用于lombok.NonNull,不适用于任何其他非空注释:这将在您的方法顶部添加一个空检查。

lombok 不为其他人这样做的原因是它的冲突:如果您将@NonNull 视为类型注释,那么它是在说:这个值不可能为空,它是有保证的,这与它的性质相反:现在空检查是编译器错误/警告!

这就像写作:

public void foo(String x) {
    if (x != null && !(x instanceof String)) throw new IllegalArgumentException("x is not a string");
}

这应该是一个编译器错误/警告,因为它不可能发生并且只是无用的代码。如果您在一个非常严格的空值系统中工作,并且会被编译器无情地检查,@NonNull 可以暗示同样的事情,因此,我们不只是添加空值检查。

@Builder

是的,那会抛出 NPE。这是因为类上的@Builder 只是@AllArgsConstructor 的语法糖(如果标记为NonNull 的字段的参数为null,它将抛出NPE),然后将@Builder 放在该全参数构造函数上。因此,构建器不会进行空检查,但构建器的 .build() 调用将调用该构造函数,它会。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-07
    • 2021-09-19
    • 2020-05-20
    • 2023-03-31
    • 2022-01-21
    • 2018-10-21
    相关资源
    最近更新 更多