对我来说,这听起来像是初级到中级开发人员在某些时候倾向于面对的一个相当常见的问题:他们要么不知道,要么不信任他们使用的对象方法,防御性地过度检查空值。此外,在编写自己的代码时,他们倾向于依靠返回空值来指示某些东西,从而要求调用者检查空值。
(1)避免NullPointerException是很容易的。从Java 1.7开始,你可以使用Objects.requireNonNull(foo)。(如果你坚持使用以前的版本,那么断言可能是一个不错的选择。)
这种方法的“正确”用法如下所示。该方法返回传入的对象,如果对象为空,则抛出NullPointerException异常。这意味着返回值总是非空的。该方法主要用于参数验证。
public Foo(Bar bar) {
this.bar = Objects.requireNonNull(bar);
}

它也可以像断言一样使用,因为如果对象为空,它会抛出异常。在这两种用法中,都可以添加一个消息,该消息将显示在异常中。下面将像使用断言一样使用它并提供消息。
Objects.requireNonNull(someobject, "如果某个对象为Null,那就是出现了错误。");
someobject.doCalc();

一般来说,当值为空但不应该为空时抛出一个特定的异常,如NullPointerException,有利于抛出一个更一般的异常,如AssertionError。这是Java库采用的方法;当参数不允许为空时,优先使用NullPointerException而不是IIlegalArgumentException。
(2)有点难。如果你不熟悉你调用的代码,对它不够了解,那么你就会陷入困境。如果null值是合理的返回,你必须检查它。但是,如果是你比较了解熟悉的代码,那么情况就不一样了,避免使用空值作为返回,使用返回集合的方法,这很简单,你可以总是返回空的集合(或数组)而不是null。
对于non-collections这可能更困难。举个例子,如果你有以下这些接口:
public interface Action {
void doSomething();
}
public interface Parser {
Action findAction(String userInput);
}

在这里,Parser接受原始用户输入并找到要做的事情,可能是在为某些东西实现接口时。现在,如果没有适当的操作,你可能会使它返回的值为空。这导致了我们正在讨论的空检查。
另一种解决方案是永远不返回null,而是使用 Null Object模式:
public class MyParser implements Parser {
private static Action DO_NOTHING = new Action() {
public void doSomething() { /* 什么都不做*/ }
};
public Action findAction(String userInput) {
// ...
if ( /* 找不到任何事件*/ ) {
return DO_NOTHING;
}
}
}
比较:
Parser parser = ParserFactory.getParser();
if (parser == null) {
// now what?
// this would be an example of where null isn't (or shouldn't be) a valid response
}
Action action = parser.findAction(someInput);
if (action == null) {
// do nothing
} else {
action.doSomething();
}
to
ParserFactory.getParser().findAction(someInput).doSomething();
这是一个更好的设计,因为它使用了更简洁的代码。
也就是说,findAction()方法抛出有意义的错误消息的Exception也许是完全合适的——特别是在依赖用户输入的情况下。findAction方法抛出异常要比调用方法抛出一个简单的NullPointerException而没有任何解释要好得多。
try {
ParserFactory.getParser().findAction(someInput).doSomething();
} catch(ActionNotFoundException anfe) {
userConsole.err(anfe.getMessage());
}
或者如果你认为尝试/捕获(try-catch)机制不好用,你默认应该向用户提供反馈,而不是什么都不做。
public Action findAction(final String userInput) {
/* 如果找到则返回请求的Action的代码 */
return new Action() {
public void doSomething() {
userConsole.err("Action not found: " + userInput);
}
}
}