空检查与可选的isPresent检查
谁能解释一下Optional
如何帮助我们避免NullPointerException
?
Optional<String> op = someFunc()
if(op.isPresent()) {
op.get();
}
String possibleNull = op.get();
此代码不是也易于NullPointerException
吗?如果是,那么为什么首选此代码而不是
String op = someFunc()
if(op != null) {
op.get();
}
String possibleNull = op;
Optional
除了帮助我们了解函数是否实际具有返回值这一事实之外,它还有什么可能的好处
解决方案
假设您要获取函数返回的字符串,将其转换为大写,然后打印出来。如果您有:
String someFunc() { ... }
您可能会想写:
System.out.println(someFunc().toUpperCase());
当然,如果someFunc
返回null
,则抛出NullPointerException
。相反,假设我们有这样的情况:
Optional<String> someFunc() { ... }
然后
System.out.println(someFunc().toUpperCase());
不起作用,因为Optional
没有toUpperCase
方法。此时--希望如此--您将面临Optional
,这应该会让您考虑Optional
为空的情况。这有助于避免NPE,但可能只是在一定程度上。
现在您可能专注于如何从Optional
中获取值,而您可能忘记了空案例。啊,有一个get
方法:
System.out.println(someFunc().get().toUpperCase());
这将带回与NPE相同的问题,只是例外是NoSuchElementException
。因此,如果您在Optional
上盲目调用get
,这实际上与在引用上调用方法而不检查它是否为空几乎是一样的。
(出于这个原因,Brian Goetz认为Optional.get
是Java 8中最大的错误。参见他在16分钟内对Angelika LangerJAX 2015 Fragen und Antworten zu Java 8的采访。我不确定这是最大的,但这是一个错误。人们只是不希望get
引发异常。)
如果您经常检查空引用或空选项,则
Optional<String> os = someFunc();
if (os.isPresent()) {
System.out.println(os.get().toUpperCase());
}
比旧的好不了多少
String s = someFunc();
if (s != null) {
System.out.println(s.toUpperCase());
}
真正的优势在于它是一个库类,具有相当丰富的API,用于以安全的方式处理空案例。通常可以通过将两个方法调用链接到最初返回Optional
的方法来处理可能包含在Optional
中的值。例如,我们可以按如下方式重写上面的示例:
someFunc().map(String::toUpperCase)
.ifPresent(System.out::println);
相关文章