我已经注意到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()。


当前回答

除了所有正确答案之外:

我们在反应流中使用它。通常产生的nullpointerexception根据它们在流中的出现情况被包装成其他异常。因此,我们以后可以很容易地决定如何处理错误。

举个例子:假设你有

<T> T parseAndValidate(String payload) throws ParsingException { ... };
<T> T save(T t) throws DBAccessException { ... };

其中parseAndValidate从ParsingException中的requireNonNull中wrapps NullPointerException。

现在你可以决定,例如什么时候重试或不重试:

...
.map(this::parseAndValidate)
.map(this::save)
.retry(Retry.<T>allBut(ParsingException.class))

如果不进行检查,将在save方法中发生NullPointerException,这将导致无休止的重试。甚至值得,想象一个长寿的订阅,补充道

.onErrorContinue(
    throwable -> throwable.getClass().equals(ParsingException.class),
    parsingExceptionConsumer()
)

现在retryextrestexception将终止您的订阅。

其他回答

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

还有一个额外的好处,静态分析工具通常知道标准库的@NonNull和@Nullable(这与显式检查null相同):

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

我认为它应该用于复制构造函数和其他一些情况,如DI,其输入参数是一个对象,你应该检查参数是否为空。 在这种情况下,您可以方便地使用此静态方法。

除了其他答案-对我来说,使用requireNonNull可以使代码更方便,(有时容易阅读)

例如,让我们检查下面的代码,

private int calculateStringLength(String input) {
        return Objects.
                requireNonNull(input, "input cannot be null").
                length();
    }

这段代码返回传递给它的字符串长度作为参数——但是如果输入为空,它将抛出一个NPE。

正如您所看到的,使用requireNonNull -没有理由再手动执行空检查了。

另一个有用的东西是“异常消息”是我自己手写的(在这种情况下输入不能为空)。

在实现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));