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

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

当前回答

如果不允许空值

如果从外部调用方法,请从以下内容开始:

public void method(Object object) {
  if (object == null) {
    throw new IllegalArgumentException("...");
  }

然后,在该方法的其余部分中,您将知道该对象不为空。

如果它是一个内部方法(不是API的一部分),只需记录它不能为空,就可以了。

例子:

public String getFirst3Chars(String text) {
  return text.subString(0, 3);
}

但是,如果您的方法只是传递值,而下一个方法传递值等,则可能会出现问题。在这种情况下,您可能需要检查上述参数。

如果允许为空

这真的取决于。如果发现我经常这样做:

if (object == null) {
  // something
} else {
  // something else
}

所以我分支,做两件完全不同的事情。没有难看的代码片段,因为我确实需要根据数据做两件不同的事情。例如,我应该处理输入,还是应该计算一个好的默认值?


实际上,我很少使用“if(object!=null&&…”这个成语。

如果你展示了你通常使用这个习语的例子,那么给你举例可能会更容易。

其他回答

您还可以使用CheckerFramework(带有JDK7及更高版本)静态检查空值。这可能会解决很多问题,但需要运行一个目前仅适用于OpenJDK AFAIK的额外工具。https://checkerframework.org/

我们一直在使用Apache库(Apache Commons)解决这个问题。

ObjectUtils.equals(object, null)

or

CollectionUtils.isEmpty(myCollection);

or

StringUtils.isEmpty("string");

作为一种实践,我喜欢前面的回答,即为集合提供初始默认值或空集,以最小化需要。

这些可以是防止出现NullPointerException或使用空集合的简单用法。这并不能回答如何处理空对象的问题,但它们为对象或集合的基本验证提供了一些检查。

希望这有帮助。

在Java8 lambdas中,可以定义以近乎完美的方式处理嵌套空检查的util方法。

void example() {
    Entry entry = new Entry();
    // This is the same as H-MANs solution 
    Person person = getNullsafe(entry, e -> e.getPerson());    
    // Get object in several steps
    String givenName = getNullsafe(entry, e -> e.getPerson(), p -> p.getName(), n -> n.getGivenName());
    // Call void methods
    doNullsafe(entry, e -> e.getPerson(), p -> p.getName(), n -> n.nameIt());        
}

/** Return result of call to f1 with o1 if it is non-null, otherwise return null. */
public static <R, T1> R getNullsafe(T1 o1, Function<T1, R> f1) {
    if (o1 != null) return f1.apply(o1);
    return null; 
}

public static <R, T0, T1> R getNullsafe(T0 o0, Function<T0, T1> f1, Function<T1, R> f2) {
    return getNullsafe(getNullsafe(o0, f1), f2);
}

public static <R, T0, T1, T2> R getNullsafe(T0 o0, Function<T0, T1> f1, Function<T1, T2> f2, Function<T2, R> f3) {
    return getNullsafe(getNullsafe(o0, f1, f2), f3);
}


/** Call consumer f1 with o1 if it is non-null, otherwise do nothing. */
public static <T1> void doNullsafe(T1 o1, Consumer<T1> f1) {
    if (o1 != null) f1.accept(o1);
}

public static <T0, T1> void doNullsafe(T0 o0, Function<T0, T1> f1, Consumer<T1> f2) {
    doNullsafe(getNullsafe(o0, f1), f2);
}

public static <T0, T1, T2> void doNullsafe(T0 o0, Function<T0, T1> f1, Function<T1, T2> f2, Consumer<T2> f3) {
    doNullsafe(getNullsafe(o0, f1, f2), f3);
}


class Entry {
    Person getPerson() { return null; }
}

class Person {
    Name getName() { return null; }
}

class Name {
    void nameIt() {}
    String getGivenName() { return null; }
}

(这个答案首先发布在这里。)

切勿将变量初始化为空。如果(1)不可能,则将所有集合和数组初始化为空集合/数组。

在您自己的代码中执行此操作,您可以避免!=空检查。

大多数时候,空检查似乎保护了集合或数组上的循环,所以只要将它们初始化为空,就不需要任何空检查。

// Bad
ArrayList<String> lemmings;
String[] names;

void checkLemmings() {
    if (lemmings != null) for(lemming: lemmings) {
        // do something
    }
}



// Good
ArrayList<String> lemmings = new ArrayList<String>();
String[] names = {};

void checkLemmings() {
    for(lemming: lemmings) {
        // do something
    }
}

这是一个很小的开销,但它值得更干净的代码和更少的NullPointerExceptions。

通过遵循问题的大多数其他答案,您可以避免很多事情,以避免NullPointerException。我只想添加Java9中引入的其他一些方法,以优雅地处理这种情况,并展示一些旧的方法也可以使用,从而减少您的工作量。

公共静态布尔值isNull(对象obj)如果提供的引用为null,则返回true,否则返回错误。自Java 1.8以来公共静态布尔值nonNull(对象obj)如果提供的引用为非null,则返回true,否则返回错误。自Java 1.8以来公共静态<T>T requireOnNullElse​(T对象,T默认对象)如果第一个参数为非null,则返回第一个参数,否则返回非空的第二个参数。自Java 9以来公共静态<T>T requireOnNullElseGet​(T obj,供应商<?扩展T>供应商)如果第一个参数为非空,则返回第一个参数,否则返回supplier.get()的非空值。自Java 9以来公共静态<T>T requireOnNull​(T obj,供应商<字符串>消息供应商)检查指定的对象引用是否为空,否则将引发自定义的NullPointerException。自Java 1.8以来

有关上述功能的更多详细信息,请参阅此处。