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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18681243/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 10:08:06  来源:igfitidea点击:

Should I use Java8/Guava Optional for every method that may return null?

javaguavaoptionaljava-8

提问by lessisawesome

Optional is used to represent nullable object, Some uses of this class include

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

  1. As a method return type, as an alternative to returning null to
    indicate that no value was available
  2. To distinguish between "unknown" (for example, not present in a map) and "known to have no value" (present in the map, with value
    Optional.absent())
  3. To wrap nullable references for storage in a collection that does not support null (though there are several other approaches to this that should be considered first)
  1. 作为方法返回类型,作为返回 null 以
    指示没有可用值的替代方法
  2. 区分“未知”(例如,不存在于地图中)和“已知没有价值”(存在于地图中,值为
    Optional.absent())
  3. 将可空引用包装在不支持 null 的集合中进行存储(尽管应该首先考虑其他几种方法)

For the first case, do I need to return Optional in all nullable return method?

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

回答by Edwin Dalorzo

So What's Wrong with Optional?

那么 Optional 有什么问题呢?

The question we face is: will JDK 8 Optional objects get rid of null references? And the answer is an emphatic no! So, detractors immediately question its value asking: then what is it good for that we couldn't already do by other means?

我们面临的问题是:JDK 8 Optional 对象会摆脱空引用吗?答案是否定的!因此,批评者立即质疑它的价值:那么我们无法通过其他方式做到的有什么好处?

Unlike functional languages like SML or Haskell which never had the concept of null references, in Java we cannot simply get rid of the null references that have historically existed. This will continue to exist, and they arguably have their proper uses (just to mention an example: three-valued logic).

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

I doubt that the intention with the Optional class is to replace every single nullable reference, but to help in the creation of more robust APIs in which just by reading the signature of a method we could tell if we can expect an optional value or not and force the programmer to use this value accordingly. But ultimately, Optional will be just another reference and subject to the same weaknesses of every other reference in the language (e.g. you could return a null Optional). It is quite evident that Optional is not going to save the day.

我怀疑 Optional 类的意图是替换每一个可为空的引用,而是帮助创建更健壮的 API,其中只需读取方法的签名,我们就可以判断我们是否可以期待可选值,以及强制程序员相应地使用这个值。但最终,Optional 将只是另一个引用,并且受到语言中所有其他引用的相同弱点的影响(例如,您可以返回一个 null Optional)。很明显,Optional 不会挽救这一天。

How these optional objects are supposed to be used or whether they are valuable or not in Java has been the matter of a heated debatein the project lambda mailing list. From the detractors we hear interesting arguments like:

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

  • The fact that other alternatives exist ( e.g. IDES like IntelliJ and Eclipse IDE support a set of proprietary annotationsfor static analysis of nullability, the JSR-305with annotations like @Nullable and @NonNull).
  • Some would like it to be usable as in the functional world, which is not entirely possible in Java since the language lacks many features existing in functional programming languages like SML or Haskell (e.g. pattern matching).
  • Others argue about how it is impossible to retrofit preexisting codeto use this idiom (e.g. List.get(Object) which will continue to return null).
  • And some complain about the fact that the lack of language support for optional values creates a potential scenario in which Optional could be used inconsistentlyin the APIs, by this creating incompatibilities, pretty much like the ones we will have with the rest of the Java API which cannot be retrofitted to use the new Optional class. This is pretty much your question here. In languages with support for optional types like in Ceylonor like in Kotlin, you would not even question this.
  • A compelling argument is that if the programmer invokes the get method in an optional object, if it is empty, it will raise a NoSuchElementException, which is pretty much the same problem that we have with nulls, just with a different exception.
  • 存在其他替代方案的事实(例如,像 IntelliJ 和 Eclipse IDE 这样的 IDES 支持一组用于可空性静态分析的专有注释JSR-305带有像 @Nullable 和 @NonNull 这样的注释)。
  • 有些人希望它像在函数世界中一样可用,这在 Java 中并不完全可行,因为该语言缺乏 SML 或 Haskell 等函数式编程语言中存在的许多特性(例如模式匹配)。
  • 其他人争论如何改造预先存在的代码以使用这个习语(例如 List.get(Object) 它将继续返回 null)。
  • 并且有些人抱怨缺乏对可选值的语言支持这一事实造成了一个潜在的场景,即 Optional在 API 中的使用可能不一致,这会导致不兼容,就像我们将与 Java API 的其余部分一样不能改装以使用新的 Optional 类。这几乎是你的问题。在CeylonKotlin支持可选类型的语言,您甚至不会质疑这一点。
  • 一个令人信服的论点是,如果程序员在一个可选对象中调用 get 方法,如果它是空的,它将引发一个 NoSuchElementException,这与我们在使用 null 时遇到的问题几乎相同,只是有一个不同的异常。

So, it would appear that the benefits of Optional are really questionable and are probably constrained to improving readability and enforcing public interface contracts.

因此,似乎 Optional 的好处确实值得怀疑,并且可能仅限于提高可读性和强制执行公共接口合同。

I do believe that the adoption of this Optional functional idiom is likely to make our code safer, less prompt to null dereferencing problems and as a result more robust and less error prone. Of course, it is not a perfect solution because, after all, Optional references can also be erroneously set to null references, but I would expect that programmers stick to the convention of not passing null references where an optional object is expected, pretty much as we today consider a good practice not to pass a null reference where a collection or an array is expected, in these cases the correct is to pass an empty array or collection. The point here is that now we have a mechanism in the API that we can use to make explicit that for a given reference we may not have a value to assign it and the user is forced, by the API, to verify that.

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

Quoting Google Guava's articleabout the use of optional objects:

引用谷歌番石榴关于使用可选对象的文章

“Besides the increase in readability that comes from giving null a name, the biggest advantage of Optional is its idiot-proof-ness. It forces you to actively think about the absent case if you want your program to compile at all, since you have to actively unwrap the Optional and address that case”.

“除了给 null 一个名字带来的可读性增加之外,Optional 的最大优势是它的白痴证明。如果你想让你的程序完全编译,它会迫使你主动考虑不存在的情况,因为你必须主动打开 Optional 并解决这种情况”。

So, I guess it's up to every API designer to choose how far they want to go in the use of Optional.

所以,我想每个 API 设计者都可以选择他们想要在使用 Optional 方面走多远。

Some influential developers like Stephen Colebourne and Brian Goetz have published a few interesting articles more recently on the proper use of optional. I particularly found useful the following:

一些有影响力的开发人员如 Stephen Colebourne 和 Brian Goetz 最近发表了一些关于正确使用 optional 的有趣文章。我特别发现以下有用:

回答by R?zvan Petruescu

As an observation, I think one of the most important aspects that have to be considered when architecting an application is to decide how to treat the "null problem". In this respect, the first step would be to identify possible "sources" of nulls. For example, the database or external libraries used in the project. The next step would be to 'contain' the problem, namely, to wrap problematic code(using Optional) and thus block the propagation of null throughout the system, where unsuspecting code might trigger NPEs.
To answer your question, it depends...Most of the times I would say that's unnecessary, since it creates a lot of work with no value (for example, I wouldn't use optional for methods that call other private methods inside classes, or for methods that call methods of package-private classes), but code that exists at the thin boundaryof different 'concerns' (or layers) in your application, (the signature of the interfaces/classes that you use to query the datastore, for example, or pojos used for 'transporting' data that might have null properties - DTOs, or, a more general description, publishedAPIs of different modules) should avoid 'leaking' nulls into some other areas with different concerns.

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

回答by Vlad

Compared with Guava, one annoying problem with java.util.Optionalis that it does not provide a method like

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

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

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

which is, on the other hand, defined in com.google.common.base.Optionalas

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

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

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

The lack of this specific feature limits monadic applications of Java 8's Optional.

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

UPDATE:

更新:

Guava's or(Optional<T>)can be replicated as in with Java 8 Optional as

Guava'sor(Optional<T>)可以像 Java 8 Optional 一样复制

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

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

or

或者

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

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

UPDATE:

更新:

In Java 9(finally!) you'll be able to use Optional.or(Supplier<Optional<T>>):

Java 9(终于!)中,您将能够使用Optional.or(Supplier<Optional<T>>)

optionalA.or(() -> computeOptionalB)

optionalA.or(() -> computeOptionalB)

That's neat!

那很整齐!