什么是番石榴的选修课的重点

我最近读了这个,看到有人在用这个类,但是在几乎所有的情况下,使用null也会起作用 – 如果不是更直观的话。 有人可以提供一个具体的例子, Optional将实现一些null不能或以一个更清洁的方式吗? 我能想到的唯一的事情就是将它用于不接受null键的Maps ,但即使这样做也可以通过空值的“映射”来完成。 任何人都可以提供一个更有说服力的论点吗? 谢谢。

番石榴团队成员在这里。

null可能最大的一个缺点是,在任何给定的上下文中,它不应该是什么意思:它没有一个说明性的名字。 这并不总是显而易见的, null意味着“这个参数没有价值” – 作为一个返回值,有时它意味着“错误”,甚至“成功”(!!),或者简单地“正确的答案是什么”。 Optional是,当你使一个variables为空时,实际上通常是这个概念,但并不总是这样。 如果不是,我们build议您编写自己的类,类似于Optional命名scheme,以明确您的实际意思。

但是我认为Optional的最大优点不在于可读性:优点是它的防白痴。 如果你想要你的程序编译的话,它会迫使你主动思考这个缺失的情况,因为你必须主动打开Optional并且处理这个事件。 Null使得简单地忘记事情变得非常容易,尽pipeFindBugs有帮助,但我认为它几乎没有解决这个问题。 当您返回可能或不可能“存在”的值时,这一点尤其重要。 您(和其他人)更有可能忘记other.method(a, b)可能会返回null值,而您可能会忘记在执行other.method时可能为null 。 返回Optional使得调用者不可能忘记这种情况,因为他们必须自己打开对象。

由于这些原因,我们build议您使用Optional作为您的方法的返回types,但不一定在您的方法参数。

(顺便说一下, 这里的讨论完全是这样的)。

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

你应该阅读以下维基百科Monad(函数式编程) :

在Kerflyn的博客上,阅读从可选到Monad与Guava ,讨论关于Guava作为Monad的可选项:


编辑:有了Java8,有一个内置的可选,像flatMap monadic运算符。 这一直是一个有争议的问题,但最终已经实施。

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); 

flatMap运算符对于允许flatMap操作是必不可less的,并允许轻松地链接所有返回可选结果的调用。

想想看,如果你使用map操作符5次,你会得到一个Optional<Optional<Optional<Optional<Optional<String>>>>> ,而使用flatMap会给你Optional<String>

从Java8以来,我宁愿不使用Guava的Optional,这个function不那么强大。

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

让我们定义一个基本的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; } 

}

现在让我们利用这个简单的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); } } 

现在让我们避免使用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()); } 

从而最终使它成为一个有意义,不含糊的方式。

可选的最重要的优点是它增加了一个函数的实现者和调用者之间的契约的更多细节。 因为这个原因对于参数和返回types都是有用的。

如果您将该约定始终设置为Optional空对象,则可以为以下情况添加更多说明:

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

    这里的合同明确指出,有一个机会,没有返回的结果,但也表明,它将起作用,并作为缺席。

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

    合约指定from是可选的,所以缺less的值可能具有特殊的含义,比如从2开始。我可以预期to参数的空值将抛出exception。

所以使用Optional的好处在于,契约变成了描述性的(类似于@NotNull注解),也是正式的,因为你必须编写代码.get()来处理Optional