3. 在Java中避免NullPointerException?| Java Debug 笔记

1,588 阅读3分钟

本文正在参加「Java主题月 - Java Debug笔记活动」,详情查看<活动链接>

提问:在Java中避免NullPointerException?

我经常使用

Object != null

的方法来避免空指针异常,有没有什么替代方法可以同样实现以下代码的功能

if (someobject != null) {
    someobject.doCalc();
}

最热门的回答: 在我看来,这似乎是一个相当普遍的问题,初级和中级开发人员往往会在某个时候遇到这些问题:他们要么不知道,要么不信任他们所参与的项目的文档,并且防御性地检查了null。另外,在编写自己的代码时,他们倾向于依靠返回空值来表示某些内容,因此要求调用者检查空值。

换句话说,在两种情况下会出现空检查:

  • 如果为null,则表示合同中的有效回复
  • 如果为null,则不是有效的回应。

第二种可以通过使用断言或抛出空指针异常来解决。

断言是1.4中新增的一个未被广泛使用的Java功能。语法为:

assert

或者

assert <condition> : <object>

其中<condition>是一个布尔表达式,<object>是一个对象,他们的toString()方法的输出将包含在错误信息中。

一个assert语句抛出一个Error。默认情况下,Java会忽略断言。您可以通过将选项传递-ea给JVM来启用断言。您可以启用和禁用单个类和程序包的断言。这意味着您可以在开发和测试时使用断言来验证代码,并在生产环境中禁用它们,尽管我的测试几乎没有显示断言对性能的影响。

在这种情况下,不使用断言是可以的,因为代码只会失败,这就是使用断言时会发生的情况。唯一的区别是,有了断言,它可能会更早地发生,以更有意义的方式出现,并可能带有额外的信息,这可以帮助您弄清楚为什么它出乎意料。

第一种情况有点难,如果null为有效响应,则必须对其进行检查。避免使用null作为响应。使用返回集合的方法很容易:通过一直返回空集合(或数组)而不是null来避免这个问题。

在不使用空集合的情况下,例如:

public interface Action {
  void doSomething();
}

public interface Parser {
  Action findAction(String userInput);
}

在这里,Parser会接受原始用户输入并找到要执行的操作,也许是在实现某项功能的命令行界面时。现在,如果没有适当的操作,您可以使函数返回null。这将导致您正在谈论的空检查。

另一种解决方案是永远不返回null,而使用Null Object模式:

public class MyParser implements Parser {
  private static Action DO_NOTHING = new Action() {
    public void doSomething() { /* do nothing */ }
  };

  public Action findAction(String userInput) {
    // ...
    if ( /* we can't find any actions */ ) {
      return DO_NOTHING;
    }
  }
}

如此编写代码,会更加简洁

对于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) {
    /* Code to return requested Action if found */
    return new Action() {
        public void doSomething() {
            userConsole.err("Action not found: " + userInput);
        }
    }
}