问题

我在Java中编程时使用最多的方法是在使用之前测试 object!= null .这是为了避免 NullPointerException .我发现代码非常丑陋,它变得不可读.

有没有一个很好的替代品?

如果要访问此对象的字段或方法,我想解决测试每个对象的必要性.例如:

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

在这种情况下,我会避免一个 NullPointerException ,我不知道是否对象是 null .因此,这些测试会在我的代码中出现.



解决方法

对我来说,这听起来像是一个普通的问题,初级到中级开发者往往会在某些时候面对:他们不知道或不信任他们参与的合同,并防守overcheck的nulls.另外,当编写自己的代码时,他们倾向于依赖返回null来表示一些东西,因此要求调用者检查null.

换句话说,有两个空检查的实例:

  1. Where null is a valid response in terms of the contract; and

  2. Where it isn't a valid response.

(2)很容易.使用 assert 语句(断言)或允许失败(例如, NullPointerException ).断言是在1.4中添加的高度低估的Java功能.语法是:

assert <condition>

assert <condition> : <object>

其中&lt; condition&gt; 是布尔表达式,&lt; object&gt; toString()在错误中.

如果条件不为真,则 assert 语句会抛出错误( AssertionError ).默认情况下,Java忽略断言.您可以通过将选项 -ea 传递到JVM来启用断言.您可以为单个类和包启用和禁用断言.这意味着您可以在开发和测试期间使用断言验证代码,并在生产环境中禁用它们,尽管我的测试显示,断言对性能没有任何影响.

在这种情况下不使用断言是确定,因为代码将失败,这是如果你使用断言会发生.唯一的区别是,断言可能会更快,更有意义的方式,可能有额外的信息,这可能会帮助你找出为什么,如果你没有期望它发生.

(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) {
  // 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();
}

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

这是一个更好的设计,因为它导致更简洁的代码.

也就是说,也许这是完全适当的findAction()方法抛出一个有意义的错误消息的异常 - 尤其是在这种情况下,你依赖于用户输入.这将是更好的findAction方法抛出一个异常比调用方法,以一个简单的NullPointerException没有解释.

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

或者如果你认为try / catch机制太丑陋,而不是Do Nothing你的默认动作应该提供反馈给用户.

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



相关问题推荐