2016-11-24 73 views
3

有人可以解释Optional如何帮助我们避免NullPointerException空检查vs可选存在检查

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提供以外的事实,它可以帮助我们知道一个函数是否真的有返回值的

+0

的可能的复制[用于可选用途]的(http://stackoverflow.com/questions/23454952/uses-for-optional) –

+1

可能的复制[可选与空。在Java 8中可选的目的是什么?](http://stackoverflow.com/questions/28746482/optional-vs-null-what-is-the-purpose-of-optional-in-java-8) – Mritunjay

+0

那么,一方面,你可以在不存在的'Optional'上使用'x.toString()',但是你不能在'null'上使用它。还有一些像'x.equals(y)'。 – ajb

回答

13

比方说,你想要获取函数返回的字符串,将其转换为大写,然后将其打印出来。如果您有:

String someFunc() { ... } 

你也许会这样写:

System.out.println(someFunc().toUpperCase()); 

当然,这将引发NullPointerException如果someFunc回报null。相反,假设我们有这样的:

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中最大的错误见他与安格兰格JAX 2015 Fragen und Antworten zu Java 8接受采访时约16分钟。我不知道这是最大的,但它是一个错误。人们只是不要指望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()); 
} 

真正优势的Optional是,它是一个库类,它具有处理以安全的方式空的情况下相当丰富的API。通常可以通过将方法调用链接到首先返回Optional的方法来处理Optional中可能包含的值。例如,以上如下,我们可以把样品:

someFunc().map(String::toUpperCase) 
      .ifPresent(System.out::println); 
+0

哇,我永远不会注意到像ifPresent这些额外的功能,谢谢。 – LegendLength