我使用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注释。

其他回答

如果不允许未定义的值:

您可以配置IDE以警告您可能的空取消引用。例如,在Eclipse中,请参阅首选项>Java>编译器>错误/警告/空分析。

如果允许未定义的值:

如果您想定义一个新的API,其中未定义的值是有意义的,请使用OptionPattern(可能在函数语言中很熟悉)。它具有以下优点:

API中明确说明是否存在输入或输出。编译器强制您处理“未定义”的情况。选项是monad,因此不需要进行冗长的空检查,只需使用map/foreach/getOrElse或类似的组合符即可安全地使用该值(示例)。

Java 8内置了可选类(推荐);对于早期版本,有一些库选项,例如Guava的Optional或FunctionalJava的Option。但是,像许多函数样式模式一样,在Java中使用Option(甚至是8)会产生一些样板,您可以使用不那么冗长的JVM语言(例如Scala或Xtend)来减少这些样板。

如果必须处理可能返回null的API,那么在Java中就做不了什么了。Xtend和Groovy有Elvis运算符?:和空安全解引用运算符?。,但请注意,如果引用为null,则返回null,因此它只是“延迟”了对null的正确处理。

有一种很好的方法来检查JDK中的空值。Optional.java有大量解决这些问题的方法。例如:

    /**
     * Returns an {@code Optional} describing the specified value, if non-null,
     * otherwise returns an empty {@code Optional}.
     *
     * @param <T> the class of the value
     * @param value the possibly-null value to describe
     * @return an {@code Optional} with a present value if the specified value
     * is non-null, otherwise an empty {@code Optional}
     */
    public static <T> Optional<T> ofNullable(T value) {
        return value == null ? empty() : of(value);
    }
    /**
     * Return {@code true} if there is a value present, otherwise {@code false}.
     *
     * @return {@code true} if there is a value present, otherwise {@code false}
     */
    public boolean isPresent() {
        return value != null;
    }
    /**
     * If a value is present, invoke the specified consumer with the value,
     * otherwise do nothing.
     *
     * @param consumer block to be executed if a value is present
     * @throws NullPointerException if value is present and {@code consumer} is
     * null
     */
    public void ifPresent(Consumer<? super T> consumer) {
        if (value != null)
            consumer.accept(value);
    }

帮助标枪真的非常非常有用。

Google集合框架为实现空检查提供了一种良好而优雅的方式。

库类中有一个方法如下:

static <T> T checkNotNull(T e) {
   if (e == null) {
      throw new NullPointerException();
   }
   return e;
}

用法是(使用import static):

...
void foo(int a, Person p) {
   if (checkNotNull(p).getAge() > a) {
      ...
   }
   else {
      ...
   }
}
...

或者在您的示例中:

checkNotNull(someobject).doCalc();

切勿将变量初始化为空。如果(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。

在Java中避免空检查的最佳方法是正确处理和使用异常。在我的经验中,随着您向前端移动,空检查变得越来越常见和必要,因为它更接近于通过UI提供无效信息的用户(例如,没有值,为字段提交)。

有人可能会争辩说,你应该能够控制UI正在做什么,以免你忘记大多数UI是通过某种类型的第三方库完成的,例如,根据情况或库的不同,它可能会为空白文本框返回NULL或空字符串。

您可以这样组合这两者:

try
{
  myvar = get_user_supplied_value(); 
  if (myvar == null || myvar.length() == 0) { alert_the_user_somehow(); return; };

  process_user_input(myvar);
} catch (Exception ex) {
  handle_exception(ex);
}

人们采取的另一种方法是:

if (myvar && myvar.length() > 0)  { };

你也可以抛出一个异常(这是我更喜欢的)

if (myvar == null || myvar.length() == 0) {
 throw new Exception("You must supply a name!");
};

但这取决于你。