在Java中,如何避免检查空值?

内容来自 DOC https://q.houxu6.top/?s=在Java中,如何避免检查空值?

我使用 x != null 来避免空指针异常。有没有其他的替代方法?

if (x != null) {
    // ...
}

在我看来,这是一个相对常见的问题,初级到中级的开发人员在某个时候都会遇到:他们要么不知道,要么不信任他们参与的合同,因此会过度检查空值。此外,在编写自己的代码时,他们倾向于依赖返回空值来表示某种情况,从而需要调用者检查空值。

换句话说,有两种情况下需要进行空值检查:

  1. 在合同中,空值是一个有效的响应;
  2. 在合同中,它不是一个有效的响应。

(2)比较容易处理。从Java 1.7开始,您可以使用Objects.requireNonNull(foo)。(如果您使用的是之前的版本,那么可以使用断言作为替代方案。)

正确使用此方法的方法如下。该方法返回传入的对象,并在对象为null时抛出NullPointerException。这意味着返回的值始终不为null。该方法主要用于验证参数。

public Foo(Bar bar) {
    this.bar = Objects.requireNonNull(bar);
}

它也可以用来像断言一样使用,因为它在对象为null时会抛出异常。在这两种用法中,都可以添加一条消息,该消息将在异常中显示。以下是像使用断言一样使用它并提供一条消息的示例。

Objects.requireNonNull(someobject, "如果someobject为null,则说明有问题");
someobject.doCalc();

通常,当值为null但不应该为null时,抛出特定的异常(如NullPointerException)比抛出更一般的异常(如AssertionError)更可取。这是Java库采取的方法;在参数不允许为null的情况下,倾向于使用NullPointerException而不是IllegalArgumentException

(1)要复杂一些。如果您无法控制要调用的代码,那么就只能这样做了。如果null是有效响应,就必须进行检查。

然而,如果您可以控制代码(而且这种情况经常发生),那么就不同了。避免将null作为响应。对于返回集合的方法,很容易:几乎总是返回空集合(或数组),而不是null。

对于非集合方法可能更难。以以下接口为例:

public interface Action {
  void doSomething();
}

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

其中Parser接收原始用户输入并找到要执行的操作,也许是因为您正在为某些命令行界面实现一个接口。现在您可能会做出这样的约定:如果没有适当的操作,它将返回null。这就引出了您所说的空值检查。

另一种解决方案是永远不要返回null,而是使用空对象模式:

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;
    }
  }
}

与下面的代码相比:

Parser parser = ParserFactory.getParser();
if (parser == null) {
  // 现在怎么办?
  // 这将是null不是(或不应该)有效响应的一个例子
}
Action action = parser.findAction(someInput);
if (action == null) {
  // 什么都不做
} else {
  action.doSomething();
}

ParserFactory.getParser().findAction(someInput).doSomething();

这是一个更好的设计,因为它导致更简洁的代码。
也就是说,也许对于findAction()方法来说,抛出一个带有有意义错误信息的异常是完全合适的-特别是在您依赖于用户输入的情况下。对于findAction方法来说,抛出一个异常比调用方法因为没有任何解释而简单地出现NullPointerException要好得多。

try {
    ParserFactory.getParser().findAction(someInput).doSomething();
} catch(ActionNotFoundException anfe) {
    userConsole.err(anfe.getMessage());
}

或者,如果您认为try/catch机制太丑陋了,那么您的默认操作应该向用户提供反馈。

public Action findAction(final String userInput) {
    /\* 如果找到请求的操作,则返回操作的代码 \*/
    return new Action() {
        public void doSomething() {
            userConsole.err("Action not found: " + userInput);
        }
    }
}
posted @ 2023-10-16 20:34  小满独家  阅读(67)  评论(0)    收藏  举报