为什么在Optional.ofNullable上使用Optional.of?

whi*_*win 206 java null nullpointerexception optional java-8

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

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

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

Tag*_*eev 269

您的问题是基于可能抛出NullPointerException的代码比不可能抛出的代码更糟糕的假设.这个假设是错误的.如果您希望foobar由于程序逻辑而永远不会为null,那么使用它会好得多,Optional.of(foobar)因为您将看到一个NullPointerException表明您的程序存在错误.如果您使用Optional.ofNullable(foobar)并且foobar碰巧是null由于该错误,那么您的程序将默默地继续正常工作,这可能是一个更大的灾难.这样一来,错误可能会在很晚之后发生,而且在理解它出错的时候会更难理解.

  • "*如果你期望你的foobar由于程序逻辑而永远不会为空,那么使用`Optional.of(foobar)`*"会好得多.这看起来有点奇怪 - 当我们知道在任何情况下值都不是"null"时,为什么不使用值本身,而不是将它包装在`Optional`中? (106认同)
  • @kocko,您可能必须从您正在实现的接口所需的方法返回`Optional`(可能其他实现者可能返回一个空的可选项).或者您想要创建一个选项集合/流,其中一些保证非空,有些则不保证.或者你有条件逻辑,它在几个分支和单个分支中创建一个可选项,你确定它是非空的. (50认同)
  • @kocko:简单的例子:`return list.isEmpty()?Optional.empty():Optional.of(list.get(0));``list`应该永远不会包含`null`值... (40认同)
  • 因为可选意味着它可以存在或不存在.缺席!= null.在这种情况下,"null"意味着"我希望foobar存在,但由于一个bug,它是null".`Optional.isPresent()== false`表示foobar不存在,即这是预期的合法行为. (26认同)
  • @Harish如果你问我,我不建议在任何地方使用Optionals.这是一个单独的问题.你可以查看一些意见[这里](http://stackoverflow.com/q/23454952/4856258). (5认同)
  • 我强烈不同意这个答案。如果您已经知道您的变量在特定情况下不能为空(如果是,则您有一个错误)用Optional包装它有什么意义? (3认同)
  • 但这不会使代码变得繁琐吗?如果我们练习添加我在类之外调用的任何方法的 Optional.of()(我希望返回非空数据),那么完整的代码库将只包含无处不在的 Optional.of() 标签? (2认同)
  • @Holger:如果为什么要使用条件运算符开头(即`return list.isEmpty()?Optional.empty():Optional.of(list.get(0));`)?为什么不只是`return list.stream().findFirst();`?这不会避免使用`Optional.of(..)`?: (2认同)

Tad*_*ato 14

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

现有答案(包括最佳答案)之所以无法正确回答该问题,是因为原来的问题一开始就不合适。如果你没有提出正确的问题,你将不会得到正确的答案。

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

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

这对不是ofand ofNullable,而是ofand empty。这是因为这两个是创建新实例的工厂方法,Optional没有提供公共构造函数。

您可以选择of何时empty创建 的新实例Optional

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

在这种用法中,您确定不会传递nullto of(),因为是您正在初始化实例。如果你想创建一个空实例,你可以直接选择empty()。因此,如果您在这个阶段传递一个null值,这显然是一个错误,您应该收到一个 NPE。of()

这个问题的一位评论者建议,由于 比ofNullable更有用,所以如果被命名为和wereof会更好。这个意见很好采纳。但是,当您考虑到和是官方工厂方法时,使用更短的名称定义更常用的方法是有意义的。此外,它也是一个很好的名称,与其他 Java 集合类工厂方法(如、、 )的命名保持一致。ofNullableofofofNotNullofemptyOptionalList#of()Set#of()Map#of()

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

String foo = someExternalAPI();
Optional<String> bar = Optional.ofNullable(foo);
Run Code Online (Sandbox Code Playgroud)

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

概括

  • 与之配对的Optional#of(T value)Optional#empty().
  • 使用ofempty创建一个新Optional实例。
  • 用于ofNullable将现有变量包装为Optional.


Kar*_*ora 8

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

String nullName = null;
String name = Optional.ofNullable(nullName).orElseThrow(NullPointerException::new);
Run Code Online (Sandbox Code Playgroud)

@ tagir-valeev,如果我错了,请更正。

  • 但是为此,您可以使用更短的`String name = Objects.requireNonNull(nullName);` (4认同)
  • 好点@Holger,但是 .orElse() 方法允许自定义异常,这可能有助于您更好地处理控制流或信息记录。 (4认同)
  • 那么,您可以为异常提供一条消息以提供附加信息。任何其他的自定义尝试,例如当问题明显是一个不应该为“null”的引用时使用与“NullPointerException”不同的异常,都将是朝着错误方向迈出的一步。 (3认同)
  • 另外,你可以使用Optional来抛出更具体的(例如自定义)异常,而不是NPE,NPE太通用了,你可以抛出类似`new NullNameException("meaningful msg")`的东西 (2认同)
  • 这不正是Optional.of(value) 所做的吗?如果值为 null 则抛出 NullPointerException? (2认同)