gpt4 book ai didi

java - 我应该一起使用@NotNull 和@NonNull 吗?

转载 作者:行者123 更新时间:2023-12-02 00:24:22 24 4
gpt4 key购买 nike

我正在使用 javax.validation.constraints.NotNull 进行 hibernate 检查空字段。现在我正在使用 lombok 来简化构造函数代码,但是我需要使用 @NonNull 注释来使字段包含在必需字段构造函数中。我应该一起使用它们吗?

最佳答案

至少有 4 完全非空注解的不同含义。大多数注释仅暗示这些不同的事物之一。因此,是的,应用多个这样的注释是有意义的。不幸的是,这些注释的实际含义相当困惑,因为根据我的经验,几乎没有开发人员考虑过它们的含义不同这一事实;事实上,我遇到的大多数开发人员都完全没有意识到空注释非常复杂且定义模糊这一事实。

类型系统解释('不能!')

这种解释是一种类型断言,它试图与 String 一样强。在 String x;是:是不可能 为此x变量引用一个不是字符串的对象,因为这是不可能的,自然地,检查这个是一个完全没用的想法。鉴于该声明,类似于 String z = (String) x太没用了,实际上是编译器警告。

这样的注释也是如此。此类示例包括 checkerframework、eclipse 和 intellij:org.checkerframeworkchecker.nullness.qual.NonNull , org.jetbrains.annotations.NotNull和 eclipse 的 org.eclipse.jdt.annotation.NonNull all 主要暗示了这个含义(尽管 intellij 适用于参数和方法,而 checkerframework 和 eclipse 是 type_use 注释。我告诉过你这很复杂:P)。

这些注释暗示“不能”,用于写时检查。出于同样的原因写作 String x = 5;是即时的,当您编写该代码时,甚至在保存文件之前,IDE 中的红色波浪下划线也是如此,例如,someMethod(map.get(key)) ,其中 someMethod 的参数用以下之一注释 NonNull注释。与其说是“你不应该”,不如说是“你不能那样做;我什至不会让你这样做”。

当然,javac 编译器实际上并不是那样工作的,IDE 和工具试图使它看起来像那样。就像您永远不会将 String 类型的变量强制转换为 String 一样,您实际上并不认为此类 null 注释暗示您应该检查。不;意思是:不是。这意味着检查已经完成,您不需要再次检查。

当然,这很复杂:围绕 Java 编译器是否实际上会阻止您打破这些非空注释的含义这一事实而跳舞……一些工具(例如 kotlinc)无论如何都会注入(inject)显式的空检查。有点像泛型如何导致 javac 在您从未编写过显式强制转换的地方注入(inject)一些类型检查,以解决泛型是编译时 bolt 连接以保持向后兼容性这一事实。这个想法是考虑这些你不应该考虑的实现细节。

数据库解释

当 hibernate 使用类作为模板以生成 CREATE TABLE 时SQL 语句,能够使用注解来设置约束和规则等很有用。出于同样的原因,您可能希望将字段标记为:“将其转换为 SQL 列时,告诉数据库引擎在其上放置唯一索引”,您可能希望将其标记为:“将其转换为 SQL 时列,告诉数据库引擎在其上放置一个非空约束”。

这与类型系统解释有关,就像枪支和祖母一样:您可以拥有代表数据库中行的对象,但由于一直打破约束而无法成功保存;例如,任何自动计数的 unid 字段通常是 ​​0,它不会像那样保存(数据库引擎将那个 0 升级为'没关系;插入没有它,让数据库引擎的序列填充这个数字)。所以它是这样的:它对 Java 根本没有任何意义; SQL 引擎将负责指示由于约束失败而导致插入/更新失败。当然,为了保存到 DB 的往返行程,并且因为这不允许简单,大多数 DB 框架会在您调用 .save() 的等效项时进行空检查。或 .store() .但这只是该数据库约束的快捷方式。

验证解释

有时java中的对象代表外部事物。例如 DB 行(与前面的含义有些重叠),或者说,用户提交的 Web 表单。这样的对象应该代表 正是它所代表的实际外部事物的实际状态。疣和无效的 gobbledygook 等等。

通常你有一个框架可以让你验证这些。这就是验证非空的含义:该字段可以为空,如果您尝试将其设置为空,则不会发生异常(因此,它们可以)。但是,只要该字段保持为空,如果您问我该对象是否有效,答案是:否。

Lombok 的解释

不幸的是,lombok 有点困惑……就像所有其他框架一样。什么 Lombok @NonNull意味着取决于它出现的位置。如果在参数上,则表示:Lombok,请在方法的第一行生成一个显式的空检查,除非我自己已经编写了它。

在字段上,这意味着:“为了 @RequiredArgsConstructor,考虑这个字段是必需的;在生成的构造函数中对其进行空检查(抛出异常)。此外,复制相关的空注释,因此,如果为这个字段..在里面添加那个空检查。”

您的具体情况

鉴于 null 注释意味着完全不同的东西,因此将多个这样的注释应用于代码中的同一构造可能并不疯狂。如果您希望数据库引擎生成 SQL NON NULL如果此类用作模板,并且对于表示此表中行的任何对象立即拒绝将其置于无效状态的任何尝试,则添加两者是有意义的。如果您希望对象表示无效状态是可以接受的,如果一般原则是构造一个空白对象,然后使用 setter 一次设置每个字段值,则几乎总是这种情况 - 然后不要添加 lombok 的注解。

你肯定已经涵盖了所有的复杂性,对吧?

连一丝微光都没有。对于真正的脑筋急转弯,请考虑 checkerframework's @PolyNull ,并考虑到这是对正确的类型系统应该真正能够处理的内容的过度简化!

免责声明:我是 Lombok 项目的核心贡献者。

关于java - 我应该一起使用@NotNull 和@NonNull 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60066012/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com