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

可选用来表示可空对象,这个类的一些用法包括

  1. 作为返回types的方法,作为返回null的替代方法
    表示没有可用的值
  2. 为了区分“未知”(例如,不存在于地图中)和“已知没有价值”(存在于地图中,具有值
    Optional.absent())
  3. 要将不可用的引用存储在不支持null的集合中(尽pipe还有其他几种应该首先考虑的方法)

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

那么什么是可选的错误?

我们面临的问题是:JDK 8可选对象是否会删除空引用? 答案是强调不! 所以,批评者立即质疑其价值:那么,有什么好处,我们已经不能用其他方式来做呢?

与从不具有空引用概念的SML或Haskell等函数式语言不同,在Java中,我们不能简单地摆脱历史上存在的空引用。 这将继续存在,他们可以说有适当的用途(仅举一个例子: 三值逻辑 )。

我怀疑用Optional类的意图是要replace每一个可空的引用,而是帮助创build更强大的API,只需读取一个方法的签名,就可以知道我们是否可以期望一个可选的值,迫使程序员相应地使用这个值。 但最终,可选将只是另一个参考,并受到语言中每个其他引用的相同弱点的影响(例如,您可以返回null可选)。 很明显,select不会挽救一天。

如何使用这些可选对象或者它们在Java中是否有价值已经成为项目lambda邮件列表中激烈辩论的问题。 我们从批评者那里听到一些有趣的论点:

  • 其他替代scheme存在的事实(例如,像IntelliJ和Eclipse IDE这样的IDES支持一组专有注释,用于静态分析的可空性, JSR-305带有@Nullable和@NonNull注释)。
  • 有些人希望它在function世界中可用,这在Java中是不完全可行的,因为语言缺乏诸如SML或Haskell之类的函数式编程语言(例如模式匹配)中存在的许多特征。
  • 其他人则争论说,如何改造现有的代码来使用这个习惯用法是不可能的(例如List.get(Object),它将继续返回null)。
  • 有些人抱怨说缺less对可选值的语言支持会创build一个潜在的场景,在这个场景中,可以在API中不一致地使用 Optional,通过这种方式创build不兼容性,就像我们在其他Java API无法使用新的可选类进行翻新。 这几乎是你的问题在这里。 在支持Ceylon 等可选types的语言中 ,您甚至不会质疑这一点。
  • 一个引人注目的观点是,如果程序员在一个可选对象中调用get方法,如果它是空的,它将引发一个NoSuchElementException,这与使用空值的问题几乎是一样的,只是有一个不同的exception。

所以,看起来,可选的好处是可疑的,可能会限制提高可读性和执行公共接口合同。

我相信采用这个可选的function方式可能会使我们的代码更安全,不会引起空引用问题,从而更健壮,更不容易出错。 当然,这不是一个完美的解决scheme,因为毕竟,可选的引用也可以被错误地设置为空引用,但我希望程序员坚持不传递空引用的约定,我们今天考虑一个好的做法,不要在需要集合或数组的情况下传递null引用,在这种情况下正确的是传递一个空的数组或集合。 这里的重点是,现在我们在API中有一个机制,我们可以使用这个机制来明确指出,对于一个给定的引用,我们可能没有分配它的值,用户被API强制validation。

引用Google Guava关于使用可选对象的文章 :

“除了赋予空名称的可读性增加之外,Optional的最大优点是它的防白痴。 如果你想要你的程序编译的话,它会迫使你主动思考这个缺席的情况,因为你必须主动打开Optional并处理这个问题“。

所以,我想这是每个APIdevise者select他们想要使用可选的多远。

一些有影响力的开发者,如Stephen Colebourne和Brian Goetz,最近发表了一些有趣的文章,关于正确使用可选的。 我特别觉得有用以下几点:

  • 如果Java Getters返回可选
  • Java SE 8可选,实用的方法

作为一个观察,我认为构build应用程序时必须考虑的最重要的方面之一是决定如何处理“空问题”。 在这方面,第一步将是确定可能的“来源”的空值。 例如,项目中使用的数据库或外部库。 下一步将是“包含”这个问题,即包装有问题的代码(使用可选的),从而阻止在整个系统中传播null,在那里不知情的代码可能触发NPE。
要回答你的问题,这取决于…大多数时候我会说这是没有必要的,因为它创造了很多没有价值的工作(例如,我不会使用可选方法调用其他私有方法,或调用包私有类的方法),而是存在于应用程序中不同“关注”(或层)的薄边界上的代码(用于查询数据存储区的接口/类的签名,例如,用于“传输”可能具有空属性的数据的pojos,DTO,或者更一般的描述,不同模块的已发布的 API)应当避免将“空值”漏入具有不同关注的其他区域。

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

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

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

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

缺less这个特定的function限制了Java 8的Optional的一元化应用。

更新:

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

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

要么

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

更新:

在Java 9 (最后!)中,你可以使用Optional.or(Supplier<Optional<T>>)

optionalA.or(() -> computeOptionalB)

那很整齐!