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

时间:2022-06-25 20:47:42

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

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

  1. As a method return type, as an alternative to returning null to
    indicate that no value was available
  2. 作为方法返回类型,作为返回null的替代方法,表示没有可用的值
  3. 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())
  4. 区分“未知”(例如,不存在于地图中)和“已知没有值”(存在于地图中,值为Optional.absent())
  5. 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)
  6. 在不支持null的集合中包装可存储的引用以进行存储(尽管还有其他几种方法应该首先考虑)

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

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

3 个解决方案

#1


72  

So What’s Wrong with 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可选对象将摆脱空引用吗?答案是强调不!因此,批评者立即质疑其价值问题:那么我们还不能通过其他方式做什么有益呢?

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不会挽救这一天。

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 debate in 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 annotations for static analysis of nullability, the JSR-305 with annotations like @Nullable and @NonNull).
  • 存在其他替代方案的事实(例如,像IntelliJ和Eclipse IDE这样的IDES支持一组用于静态分析可空性的专有注释,JSR-305带有注释,如@Nullable和@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).
  • 有些人希望它在功能世界中可以使用,这在Java中是不完全可能的,因为该语言缺少诸如SML或Haskell之类的函数编程语言中存在的许多特征(例如模式匹配)。
  • Others argue about how it is impossible to retrofit preexisting code to use this idiom (e.g. List.get(Object) which will continue to return null).
  • 其他人争论如何不可能改进预先存在的代码来使用这个习惯用法(例如List.get(Object)将继续返回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 inconsistently in 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 Ceylon or like in Kotlin, you would not even question this.
  • 有些人抱怨缺乏对可选值的语言支持会产生一种可能的情况,其中Optional可能在API中使用不一致,这会产生不兼容性,就像我们将与其他Java API一样无法改装以使用新的Optional类。这几乎是你的问题。在支持Ceylon等可选类型的语言中,或者像在Kotlin中一样,你甚至不会质疑这一点。
  • 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.
  • 一个令人信服的论点是,如果程序员在一个可选对象中调用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.

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

Quoting Google Guava's article about the use of optional objects:

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

“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这样的一些有影响力的开发者最近发表了一些有关正确使用可选项的有趣文章。我特别发现以下内容很有用:

#2


8  

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 boundary of 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, published APIs of different modules) should avoid 'leaking' nulls into some other areas with different concerns.

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

#3


7  

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

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

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

orElse(可选 ):可选

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

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

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

可以像使用Java 8 Optional as一样复制Guava或(Optional

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

optionalA.map(可选::).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 >):

optionalA.or(() -> computeOptionalB)

optionalA.or(() - > computeOptionalB)

That's neat!

那很整齐!

#1


72  

So What’s Wrong with 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可选对象将摆脱空引用吗?答案是强调不!因此,批评者立即质疑其价值问题:那么我们还不能通过其他方式做什么有益呢?

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不会挽救这一天。

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 debate in 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 annotations for static analysis of nullability, the JSR-305 with annotations like @Nullable and @NonNull).
  • 存在其他替代方案的事实(例如,像IntelliJ和Eclipse IDE这样的IDES支持一组用于静态分析可空性的专有注释,JSR-305带有注释,如@Nullable和@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).
  • 有些人希望它在功能世界中可以使用,这在Java中是不完全可能的,因为该语言缺少诸如SML或Haskell之类的函数编程语言中存在的许多特征(例如模式匹配)。
  • Others argue about how it is impossible to retrofit preexisting code to use this idiom (e.g. List.get(Object) which will continue to return null).
  • 其他人争论如何不可能改进预先存在的代码来使用这个习惯用法(例如List.get(Object)将继续返回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 inconsistently in 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 Ceylon or like in Kotlin, you would not even question this.
  • 有些人抱怨缺乏对可选值的语言支持会产生一种可能的情况,其中Optional可能在API中使用不一致,这会产生不兼容性,就像我们将与其他Java API一样无法改装以使用新的Optional类。这几乎是你的问题。在支持Ceylon等可选类型的语言中,或者像在Kotlin中一样,你甚至不会质疑这一点。
  • 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.
  • 一个令人信服的论点是,如果程序员在一个可选对象中调用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.

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

Quoting Google Guava's article about the use of optional objects:

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

“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这样的一些有影响力的开发者最近发表了一些有关正确使用可选项的有趣文章。我特别发现以下内容很有用:

#2


8  

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 boundary of 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, published APIs of different modules) should avoid 'leaking' nulls into some other areas with different concerns.

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

#3


7  

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

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

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

orElse(可选 ):可选

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

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

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

可以像使用Java 8 Optional as一样复制Guava或(Optional

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

optionalA.map(可选::).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 >):

optionalA.or(() -> computeOptionalB)

optionalA.or(() - > computeOptionalB)

That's neat!

那很整齐!