进行 Null 检查的频率和位置

How often and where to make Null-Checks

我试图避免过度的空检查,但同时我想在需要使代码健壮的时候进行空检查。但有时我觉得它开始变得如此防御,因为我没有实现 API。然后我避免了一些空检查,但是当我开始单元测试时,它开始总是等待运行时异常。什么是正确的做法,如何感受平衡。以下是我目前收集的笔记:

让我举一个让我感到困惑的虚拟例子:

这里是接口的默认功能:

default void someFunction() {

// instantiaded foo and filters
foo = processFoo(foo, filters);

// do some operations with foo
// null check if processFoo's contract returns null (description in the implementation)

}

实施:

Foo processFoo(foo, filters) {
// Should I null check foo and filters?

// Operations with foo.someFields
// Operations with filters.someFields

return foo; // If I null check then I should return some exception or null to the caller function. 
// If I don't null check just return received foo.
}

一般来说,当我控制调用时,我从不检查空值,但如果我的代码可以被其他人调用,我会强制检查,因为你说的是​​ API 规范,您可以检查输入参数并抛出 IllegalArgumentException。

当然,这不是必需的,大多数时候,当您有 NPE 时,某处存在潜在的错误,但是如果您不能完全控制调用,您肯定需要一些额外的努力。 (特别是如果你的 API 会被频繁调用,你需要一些东西来帮助你 trace/identify 糟糕的调用模式)。

在设计 API 时,除了架构本身,您还必须关注 maintenance/troubleshooting 和安全性,特别是如果 API 是公开的(这意味着还要清理每个和每个参数)。

如果您在项目中实现了分层,那么执行空值检查的好地方是从外部接收数据的层。例如:控制器,因为它从用户那里接收数据......或者网关,因为它从存储库接收数据。

但是,如果您有能力将您的方法的 return 值控制为不 return null,那就太好了。这将使您能够使用更少的空检查来编写代码,因为您可以 "ostrich" 通过这些缺失值来解决问题。 Java 为我们提供了诸如 Optional、Java 11 的 Reader.nullReader()Writer.nullWriter() 和来自 Collections.empty{List|Map|Set|...}() 的空集合等 classes/methods。

当然,您可以创建自己的 null 对象,这样它就可以在使用时以不影响程序的方式变形。

要在这里唱反调,因为似乎有些人评论似乎不喜欢 'null' 的概念或在他们的程序中使用它。

'null' 丝毫不能避免,如果你试图避免,你会遭到失败;创建对象并在内存中为此类对象分配 space 是不必要的,因为如果您的代码在接收到 'null' 值时会中断,那么在处理它根本无法处理的对象时肯定也会中断'处理。不仅如此,在使用Java的许多方法后,你同样会遭遇失败。

如果您可以避免使用 'null' 并为您的代码提供更好的工作方式,那就这样做吧。否则,不要为了避免它而折断你的背部和脊椎。


最后,回答你的问题:

当您 不确定 某些东西(例如方法)是否可以 return 一个 'null' 值时,您输入了空检查。例如,如果您调用一个您未创建的方法,并且该方法被设计为 return 一个对象,并且它可能 return 一个空值,请为这种情况添加一个特殊检查。如果您知道自己永远不会收到空值,例如您自己设计的方法永远不会 returned 'null',则无需进行任何空值检查。

此外,如果您只使用内部或私有方法,并且您知道您没有传递空参数,就像在您的示例中一样,则也没有必要添加空检查。这也适用于您提到的构造函数实例。否则,作为 public 方法中的经验法则,使用 null 检查通常是好的,即使只是为了抛出 IllegalArgumentException 或 return 失败。