我已经注意到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()。
作为旁注,在object# requireNotNull之前,在java-9之前的一些jre类中实现的这个失败速度略有不同。假设如下情况:
Consumer<String> consumer = System.out::println;
在java-8中,编译为(仅相关部分)
getstatic Field java/lang/System.out
invokevirtual java/lang/Object.getClass
基本上是一个操作:yourReference。getClass -如果你的引用为空,它将失败。
在jdk-9中发生了变化,相同的代码编译为
getstatic Field java/lang/System.out
invokestatic java/util/Objects.requireNonNull
或者基本上是对象。requireNotNull(一份)
作为旁注,在object# requireNotNull之前,在java-9之前的一些jre类中实现的这个失败速度略有不同。假设如下情况:
Consumer<String> consumer = System.out::println;
在java-8中,编译为(仅相关部分)
getstatic Field java/lang/System.out
invokevirtual java/lang/Object.getClass
基本上是一个操作:yourReference。getClass -如果你的引用为空,它将失败。
在jdk-9中发生了变化,相同的代码编译为
getstatic Field java/lang/System.out
invokestatic java/util/Objects.requireNonNull
或者基本上是对象。requireNotNull(一份)
因为这样做可以使事情显式化。如:
public class Foo {
private final Bar bar;
public Foo(Bar bar) {
Objects.requireNonNull(bar, "bar must not be null");
this.bar = bar;
}
或更短:
this.bar = Objects.requireNonNull(bar, "bar must not be null");
现在你知道了:
当使用new()成功创建Foo对象时
那么它的bar字段保证是非空的。
与此相比:今天创建了一个Foo对象,明天调用一个使用该字段并抛出的方法。最有可能的是,明天您将不知道为什么该引用昨天传递给构造函数时为空!
换句话说:通过显式地使用此方法检查传入引用,您可以控制抛出异常的时间点。大多数时候,你都想尽快失败!
主要优点是:
如前所述,控制行为
更容易调试-因为在对象创建的上下文中抛出。在某个时间点,您的日志/跟踪有一定的机会告诉您哪里出了问题!
如上所示:这个想法的真正力量与最终场相结合。因为现在类中的任何其他代码都可以安全地假设bar不为空——因此您不需要在其他地方进行任何if (bar == null)检查!