Java 为什么要使用Objects.requireNonNull()?
我注意到,Oracle JDK中的许多Java 8方法都使用Java 为什么要使用Objects.requireNonNull()?,java,java-8,nullpointerexception,Java,Java 8,Nullpointerexception,我注意到,Oracle JDK中的许多Java 8方法都使用对象。requireNonNull(),如果给定对象(参数)为null,它会在内部抛出NullPointerException public static <T> T requireNonNull(T obj) { if (obj == null) throw new NullPointerException(); return obj; } public static T requiren
对象。requireNonNull()
,如果给定对象(参数)为null
,它会在内部抛出NullPointerException
public static <T> T requireNonNull(T obj) {
if (obj == null)
throw new NullPointerException();
return obj;
}
public static T requirennull(T obj){
if(obj==null)
抛出新的NullPointerException();
返回obj;
}
但是,如果对null
对象取消引用,则仍将抛出NullPointerException
。那么,为什么要做这个额外的空检查并抛出
NullPointerException
一个显而易见的答案(或好处)是它使代码更具可读性,我同意这一点。我很想知道使用的其他原因
方法开头的
Objects.requireNonNull()
。因为这样做可以使事物显式化。比如:
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()
- 然后它的条形字段是保证的非空
- 如前所述,控制行为
- 更容易调试-因为您在对象创建的上下文中抛出。在某个时间点,您的日志/跟踪可能会告诉您出了什么问题李>
- 如上所示:这个想法的真正力量与最终领域一起展现。因为现在您的类中的任何其他代码都可以安全地假定
不是空的-因此,如果(bar==null)在其他地方进行检查,您就不需要任何bar
李>
- 只有在代码执行了一些副作用之后,才能在方法的后面使用该引用
- 在此方法中,引用可能根本不会被取消引用
- 它可以传递给完全不同的代码(即,原因和错误在代码空间中相差很远)
- 它可以在很久以后使用(即原因和错误在时间上相差很远)
- 它可以在空引用有效但具有意外效果的地方使用
NullReferenceException
(“您解除了对空值的引用”)与ArgumentNullException
(“您不应该将空值作为参数传递,而这是针对此参数的)分开来实现这一点。我希望Java也能做同样的事情,但即使只使用一个NullPointerException
,如果在可以检测到错误的最早点抛出错误,修复代码仍然容易得多。使用requirennull()
作为方法中的第一个语句,可以立即/快速识别异常的原因。stacktrace清楚地表明,由于调用方不遵守要求/约定,异常在方法输入时立即抛出。 将
null
对象传递给另一个方法确实可能会在某个时间引发异常,但问题的原因可能更复杂,因为异常将在null
对象上的特定调用中抛出,而该调用可能要远得多
下面是一个具体而真实的例子,说明了为什么我们必须支持快速失败,尤其是使用
Object.requirennull()
或任何方法对设计为非null
的参数执行无空检查
假设一个字典
类组成了一个查找服务
和一个列表
,其中字符串
表示中包含的单词。这些字段被设计为非空
,其中一个字段被传递到字典
构造函数中
现在假设Dictionary
的一个“坏”实现没有null
检查方法条目(这里是构造函数):
JVM在以下语句中抛出NPE:
return words.get(0).contains(userData);
这样,就不会让人头疼了:我们一收到异常就会抛出异常:
// exception thrown early : in the constructor
Dictionary dictionary = new Dictionary(null);
// we never arrive here
boolean isFirstElement = dictionary.isFirstElement("anyThing");
线程“main”java.lang.NullPointerException中出现异常
位于java.util.Objects.requirennull(Objects.java:203)
在com.Dictionary.(Dictionary.java:15)
位于com.Dictionary.main(Dictionary.java:24)
请注意,这里我用构造函数说明了这个问题,但方法调用可能具有相同的非空检查约束。作为旁注,在java-9之前,在一些jre类本身内部实现的
Object#requirentnull
之前,这会很快失败。假设这种情况:
Consumer<String> consumer = System.out::println;
基本上是一个操作:yourReference.getClass
——如果您的reference为null
,该操作将失败
jdk-9中的情况已经发生了变化,其中编译的代码与
getstatic Field java/lang/System.out
invokestatic java/util/Objects.requireNonNull
或者基本上是
Objects.requireNotNull(yourReference)
基本用法是立即检查并抛出NullPointerException
一个更好的选择(捷径)来满足同样的需求
public Dictionary(List<String> words) {
this.words = Objects.requireNonNull(words);
this.lookupService = new LookupService(words);
}
// exception thrown early : in the constructor
Dictionary dictionary = new Dictionary(null);
// we never arrive here
boolean isFirstElement = dictionary.isFirstElement("anyThing");
Exception in thread "main" java.lang.NullPointerException
at java.util.Objects.requireNonNull(Objects.java:203)
at com.Dictionary.(Dictionary.java:15)
at com.Dictionary.main(Dictionary.java:24)
Consumer<String> consumer = System.out::println;
getstatic Field java/lang/System.out
invokevirtual java/lang/Object.getClass
getstatic Field java/lang/System.out
invokestatic java/util/Objects.requireNonNull
@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));
<T> T parseAndValidate(String payload) throws ParsingException { ... };
<T> T save(T t) throws DBAccessException { ... };
...
.map(this::parseAndValidate)
.map(this::save)
.retry(Retry.<T>allBut(ParsingException.class))
.onErrorContinue(
throwable -> throwable.getClass().equals(ParsingException.class),
parsingExceptionConsumer()
)
private int calculateStringLength(String input) {
return Objects.
requireNonNull(input, "input cannot be null").
length();
}