为什么使用 Optional.of 而不是 Optional.ofNullable?

330

当使用Java 8的Optional类时,有两种方式将值包装为Optional。

String foobar = <value or null>;
Optional.of(foobar);         // May throw NullPointerException
Optional.ofNullable(foobar); // Safe from NullPointerException

我知道使用Optional.ofNullable是使用Optional的唯一安全方式,但为什么还存在Optional.of?为什么不始终使用Optional.ofNullable来保险呢?


1
请告诉我需要导入哪个包才能使用这个? - LoveToCode
5
如果你正在使用JDK 8或更高版本,则可以使用java.util.Optional - whirlwin
45
我很乐意为您翻译。原文意思是希望将ofNullable()的名称更改为of(),并将of()的名称更改为ofNotNull()。请看下面的翻译:我希望他们能够将ofNullable()这个名字改为of(),并且把of()这个名字改为ofNotNull() - Robert Niestroj
请参考 https://www.baeldung.com/java-optional。 - Sumesh TG
由于您正在问“为什么会有 Optional.of ?为什么不只使用 Optional.ofNullable 并始终保持安全呢?”假设用户需要的数据不存在,则我们必须抛出异常。因此,它完全取决于您的用例。 - Karan Arora
6个回答

439

你的问题基于这样一个假设:可能会抛出NullPointerException的代码比可能不会抛出的代码更糟糕。这个假设是错误的。如果你期望由于程序逻辑,你的foobar永远不会为空,那么最好使用Optional.of(foobar),因为你将会看到一个NullPointerException,这将表明你的程序存在缺陷。如果你使用Optional.ofNullable(foobar),而foobar由于程序缺陷实际上是null,那么你的程序将静默地继续工作,但结果可能是一个更大的灾难。这样,错误可能会发生得更晚,而且更难以理解它在哪个时刻出了问题。


205
如果你期望由于程序逻辑,foobar永远不会为null,那么最好使用Optional.of(foobar)。这似乎有点奇怪 - 当我们知道该值在任何情况下都不会是null时,为什么不直接使用该值,而要将其包装在Optional中呢? - Konstantin Yovkov
69
@kocko,你可能需要按照你正在实现的接口要求返回方法中的Optional(可能其他实现者会返回一个空的Optional)。或者你想创建一个包含一些保证非空和一些不确定是否为空的可选项的集合/流。或者你有条件逻辑,在几个分支创建了一个Optional,并且在单个分支中你确定它不为空。 - Tagir Valeev
33
因为 Optional 表示它可以存在,也可以不存在。Absent != null。在这种情况下,null 的意思是 “我期望 foobar 存在,但由于一个 bug 它是 null”。 Optional.isPresent() == false 意味着 foobar 不存在,即这是期望的、合法的行为。 - Buurman
48
简单例子:return list.isEmpty()? Optional.empty(): Optional.of(list.get(0)); 期望 list 永远不包含 null 值... - Holger
5
如果你在向我询问,我不建议到处都使用 Optional。那是一个不同的问题。你可以在这里查看一些观点:https://dev59.com/ymAg5IYBdhLWcg3wjrgZ。 - Tagir Valeev
显示剩余9条评论

15

此外,如果您知道当对象为null时代码不应该工作,您可以使用Optional.orElseThrow抛出异常。

String nullName = null;

String name = Optional.ofNullable(nullName)
                      .orElseThrow(NullPointerException::new);
                   // .orElseThrow(CustomException::new);

7
您可以使用更短的代码 String name = Objects.requireNonNull(nullName); 来实现此操作。 - Holger
3
不错的观点 @Holger,然而 .orElse() 方法允许自定义异常,这可能有助于更好地处理控制流或信息记录。 - Nikos Stais
5
可以为异常提供一条消息以提供额外信息。但是,对于明显是应该是非空引用而实际上是null的问题,如果试图使用不同于“NullPointerException”的异常进行自定义,这将是朝着错误方向迈出的一步。 - Holger
2
此外,您可以使用 Optional 抛出更具体的异常(例如自定义异常),而不是 NPE。NPE 太泛泛了,您可以抛出类似于 new NullNameException("有意义的消息") 的异常。 - Dáve
2
这不就是 Optional.of(value) 的作用吗?如果值为 null,就抛出 NullPointerException 吗? - motobói
@motobói 你说得对。这两种方法完全相同。不建议使用Optional.get(),因为它是新手陷阱。我认为它只是为了向后兼容而保留的。 - Soundbytes

13

这个问题已经超过七年了,但我对最佳答案感到非常沮丧,因此我不得不写出我的答案。

现有回答(包括最佳回答)未能正确回答该问题的原因在于,最初的问题本身就是不合适的。如果您没有提出正确的问题,那么您将无法得到正确的答案。

原始问题的不当之处在于它比较了错误的一对。 java.util.Optional 中有三个静态方法。

  • Optional#empty()
  • Optional#of(T value)
  • Optional#ofNullable(T value)

这对的不是ofofNullable,而是ofempty。 这是因为这两个是创建新实例的工厂方法,其中Optional不提供公共构造函数。

当您想创建Optional的新实例时,可以从ofempty中选择。

Optional<Integer> answer = Optional.of(42); // or Optional.empty() if it's absent

在这种用法中,您确定不会将null传递给of(),因为是您初始化实例。如果您想创建一个空实例,只需选择empty()即可。因此,如果您在此阶段向of()传递null值,显然是一个错误,您应该收到NPE。
在这个问题的评论者之一建议说,由于ofNullableof更有用,如果ofNullable被命名为of,而of则是ofNotNull,那么就会更好。这个观点很好。但是,当您考虑到ofempty是官方的Optional工厂方法时,使用更常见的定义具有较短的名称是有意义的。此外,它还是一个良好的名称,与其他Java集合类工厂方法的命名方式相一致,例如List#of()Set#of()Map#of()
那么什么是ofNullable?这实际上是一个实用的适配器方法,用于将消除了空值的Optional世界与充满null的传统世界桥接起来。它用于将在其他地方定义的变量或从外部服务接收到的返回值包装在Optional中,使它们具有空值安全性。
String foo = someExternalAPI();
Optional<String> bar = Optional.ofNullable(foo);

由于这是一个实用方法而不是主要工厂方法,因此给它一个稍微长一点的名称通常是可以接受的,甚至是一个好的做法,一个实用方法应该有一个描述性的名称,清楚地表明其意图。

摘要

  • Optional#of(T value) 的配对对象是 Optional#empty()
  • 使用 ofempty 创建新的 Optional 实例。
  • 使用 ofNullable 将现有变量包装为 Optional

1
这真的很清楚。非常感谢。我只是在接受答案后继续向下滚动,因为我不满意。但现在我不再需要滚动了。 - Santrupta Dash
我认为这应该是被接受的答案。解释得很清楚!:) 谢谢 - M4HdYaR

4

Optional.of和Optional.ofNullable之间的主要区别在于,如果Optional包装的元素为null,Optional.of将引发空指针异常并停止代码的进一步处理。而Optional.ofNullable只会忽略空元素/对象,并返回Optional.empty()或NoSuchElementPresent。


2

这取决于不同的情况。

比如说你有一个业务功能,并且需要进一步处理其中的值,但是如果在处理时该值为null会影响到它。

那么,在这种情况下,你可以使用Optional<?>

最初的回答。

String nullName = null;

String name = Optional.ofNullable(nullName)
                      .map(<doSomething>)
                      .orElse("Default value in case of null");

0

Optional 应该主要用于服务的结果。在服务中,您知道手头有什么,并且如果您有一个结果,则返回 Optional.of(someValue),如果没有,则返回 Optional.empty()。在这种情况下,someValue 永远不应该为 null,即使如此,您也应该返回 Optional。


1
感谢您的编辑,Sumesh。但是,您在最后一行中将“someValue”编辑为“some Value”,它引用了上面的“Optional.of(someValue)”中的变量,应该保持为someValue。 - espendennis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接