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

Why use Optional.of over Optional.ofNullable?

提问人:whirlwin 提问时间:7/29/2015 最后编辑:Andrew Tobilkowhirlwin 更新时间:5/11/2023 访问量:214995

问:

使用 Java 8 类时,有两种方法可以将值包装在可选值中。Optional

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

我知道是唯一安全的使用方式,但为什么存在呢?为什么不随时使用并保持安全呢?Optional.ofNullableOptionalOptional.ofOptional.ofNullable

java-8 nullpointerexception null 选项类型

评论

1赞 LoveToCode 10/5/2016
请告诉我必须导入哪个包才能使用它?
5赞 whirlwin 10/5/2016
@LoveToCode - 如果使用的是 JDK 8 或更高版本,则可用java.util.Optional
45赞 Robert Niestroj 6/13/2018
如果他们能命名和命名,我会很高兴ofNullable()of()of()ofNotNull()
0赞 Sumesh TG 9/11/2018
请参考 baeldung.com/java-optional
0赞 Karan Arora 5/21/2019
正如你所问的,“为什么 Optional.of 存在?为什么不直接使用 Optional.ofNullable 并始终保持安全呢?假设如果用户所需的数据不存在,那么我们必须抛出异常。因此,这完全取决于您的用例。baeldung.com/java-optional-throw-exception

答:

439赞 Tagir Valeev 7/29/2015 #1

你的问题是基于这样的假设,即可能抛出的代码比可能不会抛出的代码更糟糕。这种假设是错误的。如果您希望由于程序逻辑而永远不会为 null,那么最好使用它,因为您会看到一个 这将表明您的程序存在错误。如果你使用并且恰好是由于错误,那么你的程序将默默地继续错误地工作,这可能是一个更大的灾难。这样一来,错误可能会在很久以后发生,并且更难理解它是在什么时候出错的。NullPointerExceptionfoobarOptional.of(foobar)NullPointerExceptionOptional.ofNullable(foobar)foobarnull

评论

205赞 Konstantin Yovkov 7/29/2015
"如果你希望你的 foobar 由于程序逻辑而永远不会为 null,那么最好使用 Optional.of(foobar)”。这似乎有点奇怪 - 当我们知道该值在任何情况下都不会存在时,那么为什么不使用该值本身,而不是将其包装在一个 ?nullOptional
69赞 Tagir Valeev 7/29/2015
@kocko,您可能必须按照您正在实现的接口的要求返回 from 方法(可能其他实现者可能会返回一个空的可选选项)。或者,您想要创建可选的集合/流,其中一些保证为非 null,而另一些则不为。或者你有条件逻辑,它在多个分支中创建一个可选的,在单个分支中,你确定它是非空的。Optional
33赞 Buurman 7/29/2015
因为 Optional 意味着它可以存在,也可以不存在。缺席 != null。 在这种情况下,意味着“我希望 foobar 存在,但由于错误,它是 null”。 意味着 foobar 不存在,即这是预期的合法行为。nullOptional.isPresent() == false
48赞 Holger 7/29/2015
@kocko:简单的例子:预计永远不会包含值...return list.isEmpty()? Optional.empty(): Optional.of(list.get(0));listnull
5赞 Tagir Valeev 5/4/2016
@Harish如果你问我,我不建议到处使用可选。这是一个单独的问题。您可以在此处查看一些意见。
15赞 Karan Arora 8/14/2018 #2

此外,如果您知道如果 object 为 null,您的代码应该不起作用,则可以使用 Optional.orElseThrow 引发异常

String nullName = null;

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

评论

7赞 Holger 2/13/2019
但为此,您可以使用更短的String name = Objects.requireNonNull(nullName);
3赞 Nikos Stais 11/17/2019
@Holger但是,.orElse() 方法允许自定义异常,这可能有助于您更好地处理控制流或信息日志记录。
5赞 Holger 11/18/2019
好吧,您可以为异常提供一条消息以提供其他信息。任何其他自定义尝试,例如使用与问题显然是引用时不同的异常,而该引用不应该是引用,这将是朝着错误方向迈出的一步。NullPointerExceptionnull
2赞 Dáve 5/29/2020
另外,你可以使用 Optional 来抛出更具体(例如自定义)的 Exception,而不是 NPE,NPE 太通用了,你可以抛出类似的东西new NullNameException("meaningful msg")
2赞 motobói 6/24/2021
这不正是 Optional.of(value) 的作用吗?如果值为 null,则抛出 NullPointerException?
0赞 espendennis 9/11/2018 #3

无论如何,可选应主要用于服务的结果。在服务中,你知道你手头有什么,如果你有结果,则返回 Optional.of(someValue),如果没有,则返回 Optional.empty()。在这种情况下,someValue 永远不应为 null,并且仍然返回 Optional。

评论

1赞 espendennis 9/13/2018
感谢您对 Sumesh 的编辑,但是您编辑为“some Value”的最后一行中的“someValue”引用了上面“Optional.of(someValue)”中的变量,我认为应该保留 someValue。
2赞 Gautam 7/24/2019 #4

这取决于具体情况。

假设您有一些业务功能,并且需要进一步处理具有该值的内容,但在处理时具有该值会影响它。null

然后,在这种情况下,您可以使用 .Optional<?>

String nullName = null;

String name = Optional.ofNullable(nullName)
                      .map(<doSomething>)
                      .orElse("Default value in case of null");
4赞 Nishant 9/17/2022 #5

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

13赞 Tadayoshi Sato 5/11/2023 #6

这个问题已经有七年多的历史了,但我对最好的答案感到非常沮丧,以至于我不得不写下我的答案。

现有的答案,包括最好的答案,之所以不能正确回答问题,是因为原来的问题一开始就不合适。如果你没有设置正确的问题,你将不会得到正确的答案。

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

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

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

您可以选择 和 何时要创建 的新实例。ofemptyOptional

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

在这种用法中,您确定不会传递给 ,因为是您自己在初始化实例。如果要创建一个空实例,则可以改为选择。因此,如果你在这个阶段传递一个值,这显然是一个错误,你应该收到一个NPE。nullof()empty()nullof()

这个问题的一位评论者建议,既然 比 更有用,不如命名为 和 。这个观点很好。但是,当您考虑到它是官方的工厂方法时,使用较短的名称定义更常用的方法是有道理的。此外,它也是一个好名字,与其他 Java 集合类工厂方法(如 、 和 )的命名一致。ofNullableofofNullableofofofNotNullofemptyOptionalList#of()Set#of()Map#of()

那么什么是?这实际上是一种实用适配器方法,用于将 null 消除的世界与充满 s 的遗留世界联系起来。它用于包装在其他地方定义的变量,或从外部服务接收的返回值,以使它们对 null 安全。ofNullableOptionalnullOptional

String foo = someExternalAPI();
Optional<String> bar = Optional.ofNullable(foo);

由于这是一种实用方法而不是主工厂方法,因此通常可以接受给它一个稍长的名称,甚至最好是实用程序方法具有一个描述性名称,以清楚地说明其意图。

总结

  • 与 配对的是 .Optional#of(T value)Optional#empty()
  • 使用 或 创建新实例。ofemptyOptional
  • 用于将现有变量包装为 .ofNullableOptional

评论

1赞 Santrupta Dash 7/12/2023
这太清楚了。多谢。我只是在接受的答案后向下滚动,因为我不满意。但现在我不必再滚动了。
0赞 M4HdYaR 7/21/2023
我认为这应该是公认的答案。解释得很好!:)谢谢