如果你返回一个空数组,你需要检查“真正”的数组在哪里,以及空数组在哪里。
不要使用像
getName() != null
这样的代码,你必须使用getName().length > 0
。例如,我正在开发一个项目,在这个项目中我需要用几个压缩器压缩一些数据,并决定选择体积最小的压缩数据。如果我从压缩器“compress”方法中返回null,我需要检查返回值是否为null。如果我决定返回一个空数组,那么我还需要检查它是否为空。
我的理解正确吗?
如果你返回一个空数组,你需要检查“真正”的数组在哪里,以及空数组在哪里。
不要使用像getName() != null
这样的代码,你必须使用getName().length > 0
。例如,我正在开发一个项目,在这个项目中我需要用几个压缩器压缩一些数据,并决定选择体积最小的压缩数据。如果我从压缩器“compress”方法中返回null,我需要检查返回值是否为null。如果我决定返回一个空数组,那么我还需要检查它是否为空。
我的理解正确吗?
使用空集合或“空白”操作而不是null的主要优点是,大多数情况下,这些对象在代码中仍然可以正常工作,无需进一步修改。null值本质上更容易出现错误。
例如,考虑以下代码:
String[] names = data.getNames();
if (names != null) {
for (String name : names) {
// Do stuff
}
}
如果不检查null
,则会出现NPE错误。使用标准for循环不能解决该问题。另一方面,如果您知道始终会获得某种类型的数组,则代码将在无需额外检查的情况下正常工作。如果数组为空,则根本不会运行循环。问题得到解决。
对于实现某种操作的代码也是如此。另一个例子:
Action myAction = data.getActionToRun();
if (myAction != null) {
myAction.run();
}
再一次,你需要进行 null
检查。如果保证操作是存在的,那么你可以始终调用 action.run()
而不会产生任何副作用,然而空白操作只会什么都不做。就是这么简单。
在许多情况下,如果修改方法的返回方式,null
检查可以被简单地丢弃,从而导致更简单和易于理解的代码。在某些情况下,返回 null
是正确的选择(例如,从键值对集合中获取对象),因为没有默认的“无操作”值。但是,null
表示根本没有值,并且需要接收者进行额外处理。使用空白的、无操作的、非空对象允许数据对象处理错误。这是良好的封装。这是良好的编程。它只是有效。™
最后,返回 null
绝对不是处理错误的好方法。如果在您的代码中出现了一些应该不会出错的情况(除非您作为程序员犯了一个编程错误),请使用 assert
或异常。这些是失败。不要将 null
用作失败情况,而是将其用作简单缺少值的情况。
有时候,返回一个空数组是更自然的对象。考虑以下代码:
String [] elements = getElements();
for (String element : elements)
System.out.println(element);
我有这个想法已经有一段时间了。 暂且不谈NPE问题,我将从面向对象编程的角度来解释我的想法。
假设你编写了一个类,提供了一个Glass实例的getter方法
public Glass getGlass()
。
当我读到这个签名时,我期望得到一个Glass接口的实例,而null不是其中之一。
你可以考虑下一个方法 public Optional<Glass> getGlass()
。
Optional类(可以编写自己的或使用Google's guava Optional)包含您的通用类实例,同时提供isPresent等函数。
它可能看起来多余,因为您可以只使用getGlass() != null
而不是从客户端代码中使用getGlass().isPresent()
。但这里的主要优点是签名直观明了。没有人隐藏任何东西,你也不必猜测。
所以你可以获得以下好处:
null
,那应该就是真实的数组。如果这是一个错误情况,就抛出异常。 - Alexis Kingnull
。如果您从压缩函数收到null
,则表示出了问题。如果有错误,请抛出异常。 - Alexis King