我已经注意到Oracle JDK中的许多Java 8方法使用Objects.requireNonNull(),如果给定的对象(参数)为空,它会在内部抛出NullPointerException。

public static <T> T requireNonNull(T obj) {
    if (obj == null)
        throw new NullPointerException();
    return obj;
}

但是如果空对象被解引用,无论如何都会抛出NullPointerException。那么,为什么要做这个额外的空检查并抛出 NullPointerException吗?

一个明显的答案(或好处)是它使代码更具可读性,我同意这一点。我很想知道使用的其他原因 方法开头的Objects.requireNonNull()。


当前回答

快速失败

代码应该会尽快崩溃。它不应该做一半的工作,解引用null,然后才崩溃,只做了一半的工作,导致系统处于无效状态。

这通常被称为“早期失败”或“快速失败”。

其他回答

在实现Nullability检查的编译器扩展的上下文中(例如:uber/NullAway),对象。requireNonNull应该在某些情况下谨慎使用,例如您有一个可空字段,而您恰好知道在代码中的某个地方该字段不是空的。

这样一来,主要有两种用法:

验证 这里已经有其他回应了 运行时检查开销和潜在的NPE 可空性标记(从@Nullable更改为@Nonnull) 最小限度地使用运行时检查,以支持编译时检查 只有注释正确时才有效(由编译器强制执行)

Nullability标记用法示例:

@Nullable
Foo getFoo(boolean getNull) { return getNull ? null : new Foo(); }

// Changes contract from Nullable to Nonnull without compiler error
@Nonnull Foo myFoo = Objects.requireNonNull(getFoo(false));

NPE(空指针异常)是在你访问一个对象的成员时抛出的。Objects.requireNonNull()从访问值的位置回溯到初始化为null的位置,因此可以关注NPE的真正来源。

一个最简单的场景:

// Global String
String nullString = null;

调用空值:

public void useString() {
    nullString.length();  // The source of exception, without using Objects.requireNonNull()
}

现在如果我们在初始化时使用Objects.requireNonNull():

// Global String
String nullString = Objects.requireNonNull(null); // The source of exception which is indeed the actual source of NPE

但是如果空对象被解引用,无论如何都会抛出NullPointerException。那么,为什么要做这个额外的空检查和抛出NullPointerException?

这意味着您可以立即可靠地检测到问题。

考虑:

在代码已经执行了一些副作用之后,该引用才可能在方法的后面使用 在此方法中,引用可能根本不会被解除引用 它可以传递给完全不同的代码(即原因和错误在代码空间中相隔很远) 它可以在很久以后使用(即原因和错误在时间上相差很远) 它可以用在空引用是有效的地方,但会产生意想不到的效果

. net通过分离NullReferenceException(“你解引用了一个空值”)和ArgumentNullException(“你不应该把null作为参数传入-它是为这个参数而传入的)来更好地解决这个问题。我希望Java也能做同样的事情,但即使只有NullPointerException,如果在最早可以检测到错误的时候抛出错误,修复代码仍然容易得多。

快速失败

代码应该会尽快崩溃。它不应该做一半的工作,解引用null,然后才崩溃,只做了一半的工作,导致系统处于无效状态。

这通常被称为“早期失败”或“快速失败”。

基本用法是立即检查并抛出NullPointerException。

满足相同需求的一个更好的选择(快捷方式)是lombok的@NonNull注释。