我试图避免过度空检查,但同时我想在需要使代码健壮的时候进行空检查。但有时候我觉得它开始变得如此防守,因为我没有实现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经常被调用,您需要一些东西来帮助您跟踪/识别错误的呼叫模式)。
在设计API时,除了体系结构本身之外,还必须关注维护/故障排除和安全性,特别是如果API公开暴露(这意味着还要清理每个参数)。
如果在项目中实现了分层,那么进行空检查的好地方就是从外部接收数据的层。例如:控制器,因为它从用户...或网关接收数据,因为它从存储库接收数据。
但是如果你有能力控制你方法的返回值而不返回null
,那就不错了。这将使您能够使用较少的空检查来编写代码,因为您可以通过这样的缺失值“鸵鸟”。 Java为我们提供了类似的类/方法,如Optional
,Java 11的Reader.nullReader()
,Writer.nullWriter()
和Collections.empty{List|Map|Set|...}()
的空集合。
当然,您可以创建自己的null对象,以便它可以以一种在使用时不会影响程序的方式进行多态化。
在这里扮演魔鬼的拥护者,因为似乎有些人评论似乎不喜欢'null'的概念或在他们的程序中使用它。
“零”不是什么可以避免的,如果你试图,你将遭遇失败;创建对象并在内存中为这些对象分配空间是不必要的,因为如果你的代码在接收到'null'值时会破坏,那么在处理它根本无法处理的对象时肯定会破坏它。不仅如此,你也可以在使用Java的许多方法时遭遇失败。
如果您可以避免使用“null”并以更好的方式提供代码,请执行此操作。否则,不要打破你的背部和脊柱,以避免它。
最后,回答你的问题:
如果您不确定某个方法(如方法)是否可以返回“null”值,则输入空值检查。例如,如果您调用一个未创建的方法,并且该方法旨在返回一个对象,并且它可能返回一个空值,则为该情况添加一个特殊检查。如果你知道你永远不会收到空值,就好像你自己设计了一个方法,它永远不会返回'null',你不需要进行任何空检查。
此外,如果您只使用内部或私有方法,并且您知道没有传入null参数(如示例中所示),则也无需添加null检查。这也适用于您提到的构造函数实例。否则,作为公共方法的经验法则,通常使用空检查是好的,即使只是抛出IllegalArgumentException或返回失败。