首页 文章

我应该为每个可能返回null的方法使用Java8 / Guava Optional吗?

提问于
浏览
56

可选用于表示可为空的对象,此类的一些用途包括

  • 作为方法返回类型,作为返回null的替代方法
    表示没有可用的值

  • 区分"unknown"(例如,不存在于 Map 中)和"known to have no value"(存在于 Map 中,具有值)
    Optional.absent())

  • 在不支持null的集合中包装可存储的引用以存储(尽管还有其他几种方法应该首先考虑)

对于第一种情况,我是否需要在所有可空的返回方法中返回Optional?

3 回答

  • 72

    So What’s Wrong with Optional?

    我们面临的问题是:JDK 8可选对象将摆脱空引用吗?答案是强调不!因此,批评者立即质疑其 Value 问题:那么我们还不能通过其他方式做什么有益呢?

    与SML或Haskell这样从未有过空引用概念的函数式语言不同,在Java中我们不能简单地去除历史上存在的空引用 . 这将继续存在,他们可以说它们有适当的用途(仅举一个例子:three-valued logic) .

    我怀疑Optional类的意图是替换每一个可以为空的引用,但是为了帮助创建更强大的API,只需通过读取方法的签名,我们可以告诉我们是否可以预期可选值和强制程序员相应地使用该值 . 但最终,Optional将只是另一个引用,并且受到语言中每个其他引用的相同弱点(例如,您可以返回null可选) . 很明显,Optional不会挽救这一天 .

    如何使用这些可选对象或者它们在Java中是否有 Value 一直是项目lambda邮件列表中的heated debate问题 . 从批评者我们听到有趣的论点,如:

    • 存在其他替代方案的事实(例如,像IntelliJ和Eclipse IDE这样的IDES支持一组proprietary annotations用于可空性的静态分析,JSR-305带有@Nullable和@NonNull等注释) .

    • 有些人希望它在functional world中可以使用,这在Java中是不完全可能的,因为该语言缺少SML或Haskell等函数式编程语言中存在的许多特性(例如模式匹配) .

    • 其他人争论如何使用这个习惯用法(例如List.get(Object)将继续返回null) .

    • 有些人抱怨这样一个事实,即对可选值缺乏语言支持会产生一种可能的情况,其中可选的API可能是used inconsistently,这会产生不兼容性,就像我们将与其他Java API一样无法改装以使用新的Optional类 . 这是你的问题 . 在支持可选类型like in Ceylonlike in Kotlin的语言中,您甚至不会质疑这一点 .

    • 一个令人信服的论点是,如果程序员在可选对象中调用get方法,如果它是空的,它将引发NoSuchElementException,这与我们对null的问题几乎相同,只是有一个不同的异常 .

    因此,看起来Optional的好处确实值得怀疑,并且可能仅限于提高可读性和执行公共接口 Contract .

    我确实认为采用这种可选的功能习惯可能会使我们的代码更安全,更不能提醒null解除引用问题,因此更加健壮且不易出错 . 当然,它不是一个完美的解决方案,因为,毕竟,可选引用也可能被错误地设置为空引用,但我希望程序员坚持不传递空引用的约定,其中可选对象是预期的,几乎就像我们今天认为一个好的做法是不要在需要集合或数组的地方传递空引用,在这些情况下,正确的是传递空数组或集合 . 这里的要点是,现在我们在API中有一个机制可以用来明确表示对于给定的引用,我们可能没有值来分配它,并且API强制用户验证这一点 .

    引用Google Guava's article关于可选对象的使用:

    “除了通过赋予null名称而增加可读性之外,Optional的最大优势是它的白痴证明 . 如果你想让你的程序完全编译,它会强迫你积极思考缺席案例,因为你必须主动打开Optional并解决这个案例“ .

    所以,我想每个API设计师都可以选择他们想要使用Optional的目标 .

    像Stephen Colebourne和Brian Goetz这样的一些有影响力的开发者最近发表了一些有关正确使用可选项的有趣文章 . 我特别觉得有用了以下:

  • 8

    作为观察,我认为在构建应用程序时必须考虑的最重要方面之一是决定如何处理"null problem" . 在这方面,第一步是确定可能的"sources"空值 . 例如,项目中使用的数据库或外部库 . 下一步将是问题,即包装有问题的代码(使用Optional),从而在整个系统中阻止null的传播,其中毫无疑问的代码可能会触发NPE .
    要回答你的问题,这取决于...大多数时候我会说's unnecessary, since it creates a lot of work with no value (for example, I wouldn' t对于在类中调用其他私有方法的方法或者调用包私有类方法的方法使用可选方法,但是代码存在于应用程序中不同的'concerns'(或层)的薄 boundary (例如,用于查询数据存储区的接口/类的签名,或者用于'transporting'数据的pojos,可能具有null属性 - DTO,或者,a更一般的描述, published 不同模块的API)应该避免'leaking' null到其他一些有不同关注点的领域 .

  • 7

    与 Guava 相比, java.util.Optional 的一个令人讨厌的问题是它没有提供类似的方法

    orElse(Optional<T>): Optional<T>

    另一方面,在 com.google.common.base.Optional 中定义为

    or(Optional<T>): Optional<T>

    缺少此特定功能限制了Java 8的Optional的monadic应用程序 .

    UPDATE:

    可以像使用Java 8 Optional as一样复制Guava的 or(Optional<T>)

    optionalA.map(Optional::of).orElse(optionalB)

    要么

    optionalA.map(Optional::of).orElseGet(() -> computeOptionalB)

    UPDATE:

    Java 9(最后!)你将能够使用 Optional.or(Supplier<Optional<T>>)

    optionalA.or(() -> computeOptionalB)

    那很整齐!

相关问题