可选与空。 Java 8 中 Optional 的目的是啥? [复制]

Posted

技术标签:

【中文标题】可选与空。 Java 8 中 Optional 的目的是啥? [复制]【英文标题】:Optional vs. null. What is the purpose of Optional in Java 8? [duplicate]可选与空。 Java 8 中 Optional 的目的是什么? [复制] 【发布时间】:2015-04-29 01:37:46 【问题描述】:

在 Java 8 中,您可以返回 Optional 而不是 null。 Java 8 文档说 Optional 是“一个容器对象,它可能包含也可能不包含非空值。如果存在值,isPresent() 将返回 true,而 get() 将返回该值。”

在实践中,为什么这很有用? 另外,在任何情况下使用null 会更好吗?性能怎么样?

【问题讨论】:

性能怎么样? 【参考方案1】:

在实践中,为什么这很有用?

例如,假设你有这个整数流并且你正在做一个过滤:

int x = IntStream.of(1, -3, 5)
                 .filter(x -> x % 2 == 0)
                 .findFirst(); //hypothetical assuming that there's no Optional in the API

您事先并不知道过滤操作会删除 Stream 中的所有值。

假设 API 中没有 Optional。在这种情况下,findFirst 应该返回什么?

唯一可能的方法是抛出一个异常,例如NoSuchElementException,这在 IMO 中相当烦人,因为我认为它不应该停止你的程序的执行(或者你必须捕获异常,也不是很方便),过滤标准可能比这更复杂。

使用Optional,由调用者检查Optional 是否为空(即您的计算是否产生了值)。

对于引用类型,您还可以返回 null(但在您仅过滤 null 值的情况下,null 可能是一个可能的值;所以我们回到异常情况)。

关于非流的使用,除了防止 NPE 之外,我认为它还有助于设计一个更明确的 API 来说明值可能存在或不存在。例如考虑这个类:

class Car 
   RadioCar radioCar; //may be null or not 
   public Optional<RadioCar> getRadioCar() 
        return Optional.ofNullable(radioCar);
   

在这里,您清楚地对呼叫者说,车内的收音机是可选的,它可能存在或不存在。

【讨论】:

可选不能包含 null ... 我仍然不明白为什么 Optional 在这里是必需的。对于对象类型,我们有 null。对于原语,我们有它们的对象兄弟,例如 Integer 和 Boolean,它们也可以为 null 以表示“无值”。那么可选项有什么好处呢? @AlkisMavridis 我也很困惑为什么这个答案被如此强烈地赞成。除了 Java Stream API 可以很好地配合它之外,这里没有一个答案提供了使用 Optional&lt;T&gt; 而不是 null 的令人信服的理由。顺便说一句,Optional&lt;T&gt; 可以向开发人员提供合同提示,但适当的文档也可以...在一天结束时,您仍在检查该值是否为空,然后再对其进行操作。您刚刚将语义从 if (value == null) 更改为 if (optionalValue.isPresent())。而且您已经产生了几个方法调用的开销。 Optionals 之所以如此有用,是因为使用 Optionals 时,它会强制您以无法从null 调用方法的方式来表示数据。如果没有 Optionals,这不仅是可能的,而且非常容易。换句话说,您可以避免草率的逻辑和愚蠢的错误。它与方便或冗长几乎没有关系。 其实,在对Java和Optional做了一些研究之后,我上面的说法是not正确的。 Java 中的类型系统没有表现力,也不够强大,无法保证像 SML、F# 和 Haskell 等语言一样。即使在使用 Optionals 时,仍然可能在不存在任何值时错误地尝试获取值。那。糟透了。【参考方案2】:

在最初设计 Java 时,通常使用一个特殊的值,通常称为 null 来表示特殊情况,例如 我找不到你要找的东西。 Java 采用了这种做法。

从那时起,有人建议将这种做法视为一种反模式,尤其是对于对象而言,因为这意味着您必须在代码中乱扔空检查以实现可靠性和稳定性。例如,当您想将null 放入集合中时,这也是一种痛苦。

现代态度是使用一个特殊的对象,它可能持有也可能不持有价值。这样你就可以安全地创建一个,而不是用任何东西填充它。在这里,您看到 Java 8 通过提供 Optional 对象来鼓励这种最佳实践。

【讨论】:

你能详细说明为什么空检查是混乱的,但对 Optional.isPresent 的调用不是吗? 我也想知道... 如果您只使用 Optional 作为直接替换直接使用 Optional.isPresent 的空检查,那么它的实用性将受到限制(仍然在调用站点明确声明该值可能不存在,这很好);真正的力量来自能够推迟错误处理(无值)到以后的时间和链接 map/flatMap/filter 等方法而无需 if/else 块。 @user100464 Java 语言中的错误是它允许 null。想象一个到处都有@NonNull 的代码库。然后 Optional 可以发生 null 的地方。这提供了更安全的程序,这也是 Java 作为语言之前的发展方向(例如 C++ refs)。 Optional 通过将 map 和 flatMap 与 lambda 一起使用,消除了对条件的需求。像这样构建代码可确保不会忽略任何空检查。只是不允许调用 isPresent 并且您必须映射以获取数据并且您不会出错。 @shinzou 如果一个方法返回一个可选项,你可以立即调用 map/filter/flatMap 和它的朋友,而不用担心它是空的;但所有这些只有在它有值的情况下才会运行。当你想处理空箱时,才需要调用getOrElse和朋友来处理。【参考方案3】:

Optional 可帮助您处理可用或不可用的变量,并避免检查空引用。

【讨论】:

空引用显然不可用,否则可用,您将使用Optional#isPresent 方法安全检查 如何避免 NULL 检查?您仍然必须使用 .isPresent() 执行此操作,然后您必须执行方法调用来获取对象。所以这是更多的代码如果你调用 .of 它仍然可以抛出一个 NULL POINTER EXCEPTION 所以现在你需要一个 try/catch 块或另一个 IF 测试来测试 NULL。可选需要更多的代码而不是更少。 @BrianC 从上述 cmets 之一来看,null 检查是程序员必须有意识地做的事情,Java 在编译时不会捕捉到这一点。 Optional 帮助确保使用Optional的人知道该值可能不存在,并且在某些情况下强制程序员执行@987654325的等效操作@检查代码甚至编译。 @Populus 所以它只是一个用作合约提示的构造。明白了。 您仍在进行空检查,但现在您正在创建第二个对象来包装您的最终对象,并且必须执行虚拟方法调用来调用空检查。对我来说,它似乎效率较低。

以上是关于可选与空。 Java 8 中 Optional 的目的是啥? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

Java 8 getter 是不是应该返回可选类型?

为啥不应该在参数中使用 Java 8 的 Optional

为啥不应该在参数中使用 Java 8 的 Optional

使用 Mockito 返回 Java 8 Optional Object 的 Mocking Object 返回 Empty Optional

java lambda - 如何遍历可选列表/可选流

可选链与空值合并