空检查与可选是当前检查

有人可以解释如何帮助我们避免吗?OptionalNullPointerException

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


答案 1

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

String someFunc() { ... }

你可能会想写:

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

当然,如果返回,这将抛出。相反,假设我们有这个:NullPointerExceptionsomeFuncnull

Optional<String> someFunc() { ... }

然后

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

不起作用,因为没有方法。在这一点上 - 希望 - 你将面临一个,这应该让你想到空的情况。这有助于避免NPE,但可能只是在一定程度上。OptionaltoUpperCaseOptionalOptional

现在,您可能正在关注如何从 中获取值,而您可能会忘记空大小写。啊,有一种方法:Optionalget

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

这又带来了与 NPE 相同的问题,只是例外是相反的。因此,如果您盲目地调用 一个 ,它实际上与在不检查它是否为空的情况下在引用上调用方法几乎是一回事。NoSuchElementExceptiongetOptional

(出于这个原因,Brian Goetz认为这是Java 8中最大的错误。查看他对Angelika Langer JAX 2015 Fragen und Antworten zu Java 8的采访,大约16分钟。我不确定这是最大的,但这是一个错误。人们只是不希望抛出异常。Optional.getget

如果您勤于检查空引用或空可选选项,那么

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,用于以安全的方式处理空案例。通常可以通过将几个方法调用链接到首先返回的方法来处理可能包含的值。例如,我们可以重写上面的示例,如下所示:OptionalOptionalOptional

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

答案 2
String op = someFunc()
if(op != null) {
   op.trim();
}

当上面调用接口 someFunc() 时,它没有明确说明可以返回 null 值,因此调用方留给他/她自己的假设。

通过显式返回 Optional,someFunc() 的调用方知道该接口可能会返回 null。从界面创建者的角度来看,它允许他/她具体说明返回值,而不必单独记录它。

Optional<String> op = someFunc()
if(op.isPresent()) {
   op.get().trim();
}