@NonNull 会在使用@NoArgsConstructor 时出错吗?

Will @NonNull give an error on using @NoArgsConstructor?

@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 行遇到任何错误吗?

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

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

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

Lombok 将 final 的任何字段都视为具有某种 NonNull 注释,它特别识别为暗示任何对象都不应该甚至存在于该字段为空的地方(特别是 排除 JPA 的 NotNull!),并且可以在 lombok.config 中配置,但是 lombok 附带了一组开箱即用的已知注释集,作为 'required'.

'required' 字段具有以下属性:

  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 将这些字段保留为空,并假定您知道自己在做什么。通常,您制作这些构造函数是因为框架要求您这样做,或者因为框架会 'fix' 通过立即调用一堆 setter 或反射更新这些字段来将字段标记为永不为 null 且包含空值的问题.

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

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

@lombok.NonNull 参数

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

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

就像写作:

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

那应该是一个编译器 error/warning 因为它不可能发生而且只是无用的代码。如果你在一个非常严格的 nullity 系统中工作,你的编译器会无情地检查它,@NonNull 可能意味着同样的事情,因此,我们不只是添加 null 检查。

@Builder

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