我使用x!=null以避免NullPointerException。还有其他选择吗?

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

当前回答

如果您使用(或计划使用)JetBrains IntelliJ IDEA、Eclipse或Netbeans等Java IDE或findbugs等工具,那么您可以使用注释来解决这个问题。

基本上,你有@Nullable和@NotNull。

您可以在方法和参数中使用,如下所示:

@NotNull public static String helloWorld() {
    return "Hello World";
}

or

@Nullable public static String helloWorld() {
    return "Hello World";
}

第二个示例无法编译(在IntelliJ IDEA中)。

在另一段代码中使用第一个helloWorld()函数时:

public static void main(String[] args)
{
    String result = helloWorld();
    if(result != null) {
        System.out.println(result);
    }
}

现在IntelliJ IDEA编译器将告诉您,检查是无用的,因为helloWorld()函数永远不会返回null。

使用参数

void someMethod(@NotNull someParameter) { }

如果你写的东西像:

someMethod(null);

这无法编译。

最后一个使用@Nullable的示例

@Nullable iWantToDestroyEverything() { return null; }

这样做

iWantToDestroyEverything().something();

你可以肯定这不会发生。:)

这是一个很好的方法,可以让编译器检查比通常更多的东西,并强制执行您的契约以使其更强大。不幸的是,并非所有编译器都支持它。

在IntelliJ IDEA 10.5及更高版本中,他们添加了对任何其他@Nullable@NotNull实现的支持。

查看博客文章更灵活和可配置的@Nullable/@NotNull注释。

其他回答

对于Java8或更新版本,最好的选择可能是使用Optional类。

Optional stringToUse = Optional.of("optional is there");
stringToUse.ifPresent(System.out::println);

这对于可能的空值的长链来说尤其方便。例子:

Optional<Integer> i = Optional.ofNullable(wsObject.getFoo())
    .map(f -> f.getBar())
    .map(b -> b.getBaz())
    .map(b -> b.getInt());

如何在null上引发异常的示例:

Optional optionalCarNull = Optional.ofNullable(someNull);
optionalCarNull.orElseThrow(IllegalStateException::new);

Java7引入了Objects.requireOnNull方法,当需要检查某些内容是否为非空时,该方法非常方便。例子:

String lowerVal = Objects.requireNonNull(someVar, "input cannot be null or empty").toLowerCase();

您可以考虑空对象是bug的情况,而不是空对象模式(有其用途)。

当抛出异常时,检查堆栈跟踪并解决错误。

好的,我现在已经从技术上回答了一百万次,但我不得不这么说,因为这是一场与Java程序员的无休止的讨论。

很抱歉,我不同意以上所有内容。我们必须在Java中测试null的原因是,Java程序员一定不知道如何处理内存。

我这么说是因为我有很长的C++编程经验,而我们不这么做。换句话说,你不需要这样做。注意,在Java中,如果你命中了一个悬空指针,你会得到一个正常的异常;在C++中,此异常通常不会被捕获并终止程序。

不想这样做吗?然后遵循C/C++中的一些简单规则。

不要轻易实例化事物,认为每一个“新”都会给你带来很多麻烦,并遵循这些简单的规则。

一个类只能通过3种方式访问内存->

它可以“拥有”类成员,他们将遵循以下规则:所有“HAS”成员都是在构造函数中“新建”的。您将在析构函数或等效的close()中关闭/取消分配同一类的Java函数,而不是其他类。

这意味着您需要记住(就像Java一样)谁是每个资源的所有者或父级,并尊重该所有权。对象只能由创建它的类删除。此外->

一些成员将被“使用”,但不拥有或“拥有”。这是另一个类中的“OWN”,并作为参数传递给构造函数。由于这些是由另一个类拥有的,我们永远不会删除或关闭它,只有父类才能删除或关闭。类中的方法还可以实例化本地对象供内部使用,这些对象永远不会传递到类的外部,或者它们应该是正常的“有”对象。

最后,要使所有这些工作正常进行,您需要有一个严格的设计,以层次结构形式使用类,并且不进行循环。

在这种设计下,遵循上述规则,层次结构设计中的子类不可能访问被破坏的指针,因为这意味着父类在子类之前被破坏,而层次结构非循环设计不允许这样做。

最后,还要记住,在启动系统时,应该从上到下构建层次结构,并从下到上销毁。任何地方都不会有空指针,或者有人违反了规则。

在我看来,这似乎是初级到中级开发人员在某个时候往往会面临的一个相当普遍的问题:他们要么不知道,要么不信任他们正在参与的合同,并防御性地过度检查空值。此外,在编写自己的代码时,他们倾向于依赖于返回null来指示某些内容,从而要求调用者检查null。

换言之,有两种情况会出现空检查:

在合同条款中,null为有效响应;和如果它不是有效的响应。

(2) 很容易。从Java1.7开始,您可以使用Objects.requireOnNull(foo)

该方法的“正确”用法如下。该方法返回传递给它的对象,如果对象为空,则抛出NullPointerException。这意味着返回的值总是非空的。该方法主要用于验证参数。

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

它也可以像断言一样使用,因为如果对象为空,它会抛出异常。在这两种情况下,都可以添加一条消息,该消息将显示在异常中。下面将其用作断言并提供消息。

Objects.requireNonNull(someobject, "if someobject is null then something is wrong");
someobject.doCalc();

当值为null但不应为null时,通常会引发特定异常(如NullPointerException),这有利于引发更一般的异常(如AssertionError)。这是Java库采用的方法;当参数不允许为null时,支持NullPointerException而不是IllegalArgumentException。

(1) 有点难。如果你无法控制正在调用的代码,那么你就被卡住了。如果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();
}

to

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

Java7有一个新的Java.util.Objects实用程序类,其中有一个requireOnNull()方法。如果它的参数为null,那么它只会抛出一个NullPointerException,但它会稍微清理代码。例子:

Objects.requireNonNull(someObject);
someObject.doCalc();

该方法对于在构造函数中进行赋值之前进行检查非常有用,每次使用它都可以节省三行代码:

Parent(Child child) {
   if (child == null) {
      throw new NullPointerException("child");
   }
   this.child = child;
}

变成

Parent(Child child) {
   this.child = Objects.requireNonNull(child, "child");
}