空检查与可选检查是否存在

2020年6月20日 46点热度 0条评论

有人可以解释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());

当然,如果
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。因此,如果您盲目地在
get上调用
Optional,则与在不检查是否为空的情况下在引用上调用方法几乎一样。

(由于这个原因,
Brian Goetz认为
Optional.get是Java 8中最大的错误。请在大约16分钟的时间里接受他对Angelika Langer
JAX 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());
}

Optional的真正优势在于,它是一个具有非常丰富的API的库类,可以安全地处理空的情况。通常可以通过将几个方法调用链接到首先返回
Optional的方法来处理
Optional中可能包含的值。例如,我们可以按以下方式重写上面的示例:

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