Guava的Optional课程有什么意义

时间:2021-02-18 20:46:37

I've recently read about this and seen people using this class, but in pretty much all cases, using null would've worked as well - if not more intuitively. Can someone provide a concrete example where Optional would achieve something that null couldn't or in a much cleaner way? The only thing I can think of is to use it with Maps that don't accept null keys, but even that could be done with a side "mapping" of null's value. Can anyone provide me with a more convincing argument? Thank you.

我最近读过这篇文章并看过人们使用这个类,但在几乎所有情况下,使用null都会起作用 - 如果不是更直观的话。有人能提供一个具体的例子,其中Optional可以实现null无法或更清洁的方式吗?我唯一能想到的是将它与不接受空键的Maps一起使用,但即便如此,也可以通过null的值的“映射”来完成。任何人都可以给我一个更有说服力的论点吗?谢谢。

4 个解决方案

#1


Guava team member here.

番石榴团队成员在这里。

Probably the single biggest disadvantage of null is that it's not obvious what it should mean in any given context: it doesn't have an illustrative name. It's not always obvious that null means "no value for this parameter" -- heck, as a return value, sometimes it means "error", or even "success" (!!), or simply "the correct answer is nothing". Optional is frequently the concept you actually mean when you make a variable nullable, but not always. When it isn't, we recommend that you write your own class, similar to Optional but with a different naming scheme, to make clear what you actually mean.

null的最大缺点可能是它在任何给定的上下文中它应该意味着什么并不明显:它没有说明性的名称。并不总是显而易见的是,null表示“此参数没有值” - 哎,作为返回值,有时它意味着“错误”,甚至“成功”(!!),或者简单地说“正确的答案是什么”。可选的通常是当你使变量可为空时实际意味着的概念,但并非总是如此。如果不是,我们建议您编写自己的类,类似于Optional,但使用不同的命名方案,以明确您的实际含义。

But I would say the biggest advantage of Optional isn't in readability: the advantage 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 makes it disturbingly easy to simply forget things, and though FindBugs helps, I don't think it addresses the issue nearly as well. This is especially relevant when you're returning values that may or may not be "present." You (and others) are far more likely to forget that other.method(a, b) could return a null value than you're likely to forget that a could be null when you're implementing other.method. Returning Optional makes it impossible for callers to forget that case, since they have to unwrap the object themselves.

但我要说的是,Optional的最大优势在于可读性:优点是它的白痴证明。如果您希望程序完全编译,它会强制您主动考虑缺席情况,因为您必须主动解包可选并解决该情况。 Null使得简单地忘记事情变得非常容易,虽然FindBugs有所帮助,但我认为它几乎不能解决这个问题。当您返回可能存在或可能不存在的值时,这尤其重要。你(和其他人)更有可能忘记other.method(a,b)可以返回一个空值而不是你可能会忘记当你实现other.method时a可能为null。返回Optional使得调用者无法忘记这种情况,因为他们必须自己解开对象。

For these reasons, we recommend that you use Optional as a return type for your methods, but not necessarily in your method arguments.

出于这些原因,我们建议您使用Optional作为方法的返回类型,但不一定在方法参数中。

(This is totally cribbed, by the way, from the discussion here.)

(顺便说一句,从这里的讨论来看,这完全是残缺的。)

#2


It really looks like the Maybe Monad pattern from Haskell.

它看起来真的像Haskell的Maybe Monad模式。

You should read the following, Wikipedia Monad (functional programming):

您应该阅读以下内容,Wikipedia Monad(函数式编程):

And read From Optional to Monad with Guava on Kerflyn's Blog, which discusses about the Optional of Guava used as a Monad:

在Kerflyn的博客上阅读From Optional to Monad with Guava,其中讨论了用作Monad的Guava的可选性:


Edit:With Java8, there's a built-in Optional that has monadic operators like flatMap. This has been a controversial subject but finally has been implemented.

编辑:使用Java8,有一个内置的Optional,它有像flatMap这样的monadic运算符。这是一个有争议的话题,但最终已经实施。

See http://www.nurkiewicz.com/2013/08/optional-in-java-8-cheat-sheet.html

public Optional<String> tryFindSimilar(String s)  //...Optional<Optional<String>> bad = opt.map(this::tryFindSimilar);Optional<String> similar =       opt.flatMap(this::tryFindSimilar);

The flatMap operator is essential to allow monadic operations, and permits to easily chain calls that all return Optional results.

flatMap运算符对于允许monadic操作至关重要,并允许轻松链接所有返回Optional结果的调用。

Think about it, if you used the map operator 5 times you would end up with an Optional<Optional<Optional<Optional<Optional<String>>>>>, while using flatMap would give you Optional<String>

想想看,如果你使用map运算符5次,你最终会得到一个Optional >>>>,而使用flatMap会给你Optional

Since Java8 I would rather not use Guava's Optional which is less powerful.

从Java8开始,我宁愿不使用功能较弱的Guava的Optional。

#3


One good reason to use it is that it makes your nulls very meaningful. Instead of returning a null that could mean many things (like error, or failure, or empty,etc) you can put a 'name' to your null. Look at this example:

使用它的一个很好的理由是它使你的空值非常有意义。您可以在null中添加“名称”,而不是返回可能意味着很多事情的空(例如错误,失败或空等)。看看这个例子:

lets define a basic POJO:

让我们定义一个基本的POJO:

class PersonDetails {String person;String comments;public PersonDetails(String person, String comments) {    this.person = person;    this.comments = comments;}public String getPerson() {    return person;}public String getComments() {    return comments;}

}

Now lets make use of this simple POJO:

现在让我们使用这个简单的POJO:

public Optional<PersonDetails> getPersonDetailstWithOptional () {  PersonDetails details = null; /*details of the person are empty but to the caller this is meaningless,  lets make the return value more meaningful*/    if (details == null) {      //return an absent here, caller can check for absent to signify details are not present        return Optional.absent();    } else {      //else return the details wrapped in a guava 'optional'        return Optional.of(details);       }}

Now lets avoid using null and do our checks with Optional so its meaningful

现在让我们避免使用null并使用Optional进行检查以使其有意义

public void checkUsingOptional () {    Optional<PersonDetails> details = getPersonDetailstWithOptional();    /*below condition checks if persons details are present (notice we dont check if person details are null,    we use something more meaningful. Guava optional forces this with the implementation)*/    if (details.isPresent()) {      PersonDetails details = details.get();        // proceed with further processing        logger.info(details);    } else {        // do nothing        logger.info("object was null");     }    assertFalse(details.isPresent());}

thus in the end its a way to make nulls meaningful, & less ambiguity.

因此最终它是一种使空值有意义且不那么模糊的方法。

#4


The most important advantage of Optional is that it adds more details to the contract between the implementer and caller of a function. For this reason is both useful for parameters and return type.

Optional的最重要优点是它为函数的实现者和调用者之间的契约添加了更多细节。因此,这对参数和返回类型都很有用。

If you make the convention to always have Optional for possible null objects you add more clarifications to cases like:

如果使约定始终对可能的null对象具有Optional,则可以对以下情况添加更多说明:

  1. Optional<Integer> maxPrime(Optional<Integer> from, Optional<Integer> to)

    可选 maxPrime(可选 from,Optional to)

    The contract here clearly specifies that there is a chance that a result is not returned but also shows that it will work with from and to as absent.

    这里的合同明确规定,有可能不返回结果,但也表明它将与缺席一起工作。

  2. Optional<Integer> maxPrime(Optional<Integer> from, Integer to)

    可选 maxPrime(可选 from,Integer to)

    The contract specifies that the from is optional so an absent value might have a special meaning like start from 2. I can expect that a null value for the to parameter will throw an exception.

    合同指定from是可选的,因此缺席值可能具有特殊含义,例如从2开始。我可以预期to参数的null值将引发异常。

So the good part of using Optional is that the contract became both descriptive (similar with @NotNull annotation) but also formal since you must write code .get() to cope with Optional.

因此,使用Optional的好处是合同既具有描述性(类似于@NotNull注释),也是正式的,因为您必须编写代码.get()来处理Optional。

#1


Guava team member here.

番石榴团队成员在这里。

Probably the single biggest disadvantage of null is that it's not obvious what it should mean in any given context: it doesn't have an illustrative name. It's not always obvious that null means "no value for this parameter" -- heck, as a return value, sometimes it means "error", or even "success" (!!), or simply "the correct answer is nothing". Optional is frequently the concept you actually mean when you make a variable nullable, but not always. When it isn't, we recommend that you write your own class, similar to Optional but with a different naming scheme, to make clear what you actually mean.

null的最大缺点可能是它在任何给定的上下文中它应该意味着什么并不明显:它没有说明性的名称。并不总是显而易见的是,null表示“此参数没有值” - 哎,作为返回值,有时它意味着“错误”,甚至“成功”(!!),或者简单地说“正确的答案是什么”。可选的通常是当你使变量可为空时实际意味着的概念,但并非总是如此。如果不是,我们建议您编写自己的类,类似于Optional,但使用不同的命名方案,以明确您的实际含义。

But I would say the biggest advantage of Optional isn't in readability: the advantage 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 makes it disturbingly easy to simply forget things, and though FindBugs helps, I don't think it addresses the issue nearly as well. This is especially relevant when you're returning values that may or may not be "present." You (and others) are far more likely to forget that other.method(a, b) could return a null value than you're likely to forget that a could be null when you're implementing other.method. Returning Optional makes it impossible for callers to forget that case, since they have to unwrap the object themselves.

但我要说的是,Optional的最大优势在于可读性:优点是它的白痴证明。如果您希望程序完全编译,它会强制您主动考虑缺席情况,因为您必须主动解包可选并解决该情况。 Null使得简单地忘记事情变得非常容易,虽然FindBugs有所帮助,但我认为它几乎不能解决这个问题。当您返回可能存在或可能不存在的值时,这尤其重要。你(和其他人)更有可能忘记other.method(a,b)可以返回一个空值而不是你可能会忘记当你实现other.method时a可能为null。返回Optional使得调用者无法忘记这种情况,因为他们必须自己解开对象。

For these reasons, we recommend that you use Optional as a return type for your methods, but not necessarily in your method arguments.

出于这些原因,我们建议您使用Optional作为方法的返回类型,但不一定在方法参数中。

(This is totally cribbed, by the way, from the discussion here.)

(顺便说一句,从这里的讨论来看,这完全是残缺的。)

#2


It really looks like the Maybe Monad pattern from Haskell.

它看起来真的像Haskell的Maybe Monad模式。

You should read the following, Wikipedia Monad (functional programming):

您应该阅读以下内容,Wikipedia Monad(函数式编程):

And read From Optional to Monad with Guava on Kerflyn's Blog, which discusses about the Optional of Guava used as a Monad:

在Kerflyn的博客上阅读From Optional to Monad with Guava,其中讨论了用作Monad的Guava的可选性:


Edit:With Java8, there's a built-in Optional that has monadic operators like flatMap. This has been a controversial subject but finally has been implemented.

编辑:使用Java8,有一个内置的Optional,它有像flatMap这样的monadic运算符。这是一个有争议的话题,但最终已经实施。

See http://www.nurkiewicz.com/2013/08/optional-in-java-8-cheat-sheet.html

public Optional<String> tryFindSimilar(String s)  //...Optional<Optional<String>> bad = opt.map(this::tryFindSimilar);Optional<String> similar =       opt.flatMap(this::tryFindSimilar);

The flatMap operator is essential to allow monadic operations, and permits to easily chain calls that all return Optional results.

flatMap运算符对于允许monadic操作至关重要,并允许轻松链接所有返回Optional结果的调用。

Think about it, if you used the map operator 5 times you would end up with an Optional<Optional<Optional<Optional<Optional<String>>>>>, while using flatMap would give you Optional<String>

想想看,如果你使用map运算符5次,你最终会得到一个Optional >>>>,而使用flatMap会给你Optional

Since Java8 I would rather not use Guava's Optional which is less powerful.

从Java8开始,我宁愿不使用功能较弱的Guava的Optional。

#3


One good reason to use it is that it makes your nulls very meaningful. Instead of returning a null that could mean many things (like error, or failure, or empty,etc) you can put a 'name' to your null. Look at this example:

使用它的一个很好的理由是它使你的空值非常有意义。您可以在null中添加“名称”,而不是返回可能意味着很多事情的空(例如错误,失败或空等)。看看这个例子:

lets define a basic POJO:

让我们定义一个基本的POJO:

class PersonDetails {String person;String comments;public PersonDetails(String person, String comments) {    this.person = person;    this.comments = comments;}public String getPerson() {    return person;}public String getComments() {    return comments;}

}

Now lets make use of this simple POJO:

现在让我们使用这个简单的POJO:

public Optional<PersonDetails> getPersonDetailstWithOptional () {  PersonDetails details = null; /*details of the person are empty but to the caller this is meaningless,  lets make the return value more meaningful*/    if (details == null) {      //return an absent here, caller can check for absent to signify details are not present        return Optional.absent();    } else {      //else return the details wrapped in a guava 'optional'        return Optional.of(details);       }}

Now lets avoid using null and do our checks with Optional so its meaningful

现在让我们避免使用null并使用Optional进行检查以使其有意义

public void checkUsingOptional () {    Optional<PersonDetails> details = getPersonDetailstWithOptional();    /*below condition checks if persons details are present (notice we dont check if person details are null,    we use something more meaningful. Guava optional forces this with the implementation)*/    if (details.isPresent()) {      PersonDetails details = details.get();        // proceed with further processing        logger.info(details);    } else {        // do nothing        logger.info("object was null");     }    assertFalse(details.isPresent());}

thus in the end its a way to make nulls meaningful, & less ambiguity.

因此最终它是一种使空值有意义且不那么模糊的方法。

#4


The most important advantage of Optional is that it adds more details to the contract between the implementer and caller of a function. For this reason is both useful for parameters and return type.

Optional的最重要优点是它为函数的实现者和调用者之间的契约添加了更多细节。因此,这对参数和返回类型都很有用。

If you make the convention to always have Optional for possible null objects you add more clarifications to cases like:

如果使约定始终对可能的null对象具有Optional,则可以对以下情况添加更多说明:

  1. Optional<Integer> maxPrime(Optional<Integer> from, Optional<Integer> to)

    可选 maxPrime(可选 from,Optional to)

    The contract here clearly specifies that there is a chance that a result is not returned but also shows that it will work with from and to as absent.

    这里的合同明确规定,有可能不返回结果,但也表明它将与缺席一起工作。

  2. Optional<Integer> maxPrime(Optional<Integer> from, Integer to)

    可选 maxPrime(可选 from,Integer to)

    The contract specifies that the from is optional so an absent value might have a special meaning like start from 2. I can expect that a null value for the to parameter will throw an exception.

    合同指定from是可选的,因此缺席值可能具有特殊含义,例如从2开始。我可以预期to参数的null值将引发异常。

So the good part of using Optional is that the contract became both descriptive (similar with @NotNull annotation) but also formal since you must write code .get() to cope with Optional.

因此,使用Optional的好处是合同既具有描述性(类似于@NotNull注释),也是正式的,因为您必须编写代码.get()来处理Optional。