Guava的Optional课程有什么意义

RAY*_*RAY 87 java generics guava

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

Lou*_*man 153

番石榴团队成员在这里.

可能最大的缺点null是,在任何给定的环境中,它的含义并不明显:它没有说明性的名称.这并不总是显而易见的null意思是"这个参数没有价值" - 作为一个返回值,有时它意味着"错误",甚至"成功"(!!),或者只是"正确的答案是什么".Optional当你将变量变为可空时,这通常是你实际意味着的概念,但并非总是如此.如果不是,我们建议您编写自己的类,类似Optional但使用不同的命名方案,以明确您的实际含义.

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

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

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

  • 已经确定如果键未映射,`Map`返回'null`,但回想一下,如果你执行`map.put(key,null)`,那么`map.containsKey(key)`将返回`true`但是`map.get(key)`将返回`null`."可选"可以很方便地清除"显式映射到空"的情况和"不存在于地图"的情况之间的区别.我会批准"可选"可以被滥用,但我还不确定你描述的案例是滥用. (9认同)
  • 使用过时的类比,曾经有过这些称为"电话簿"的巨型东西:-)如果我要求你查找某人的号码而你说"那个人没有号码",我会说"你是什么人"意思是,他们在那里有一个未列出的号码,或者你根本找不到他们的条目?" 这两个可能的响应分别很好地映射到Optional.absent()和null.Optional.absent()是明确的"正面否定". (8认同)
  • +1给出了很好的解释.我不知道这是否是灵感,但我会在SML,OCaml和F#中添加指向选项类型的指针,它们具有许多相同的语义. (3认同)
  • @RAY:在某种程度上,`Optional <T>`**是**"找到但无效"的值.或者更准确地说,`Optional <T>`是一种[装饰](http://en.wikipedia.org/wiki/Decorator_pattern)任何类型`T`的方法,带有额外的"找到但无效"值 - 通过组合两个现有类型来创建新类型.如果你有一百个类,那么为每个类创建一个单独的"找到但无效"的值会变得很混乱,但是`Optional <T>`可以很容易地为所有这些值工作. (3认同)
  • 总是很乐意从直接参与的人那里得到答案.我只为此+1了.为了一个好的答案,还会+1.(但我不能.)我认为将其作为一种回报价值迫使消费者使用一种不熟悉的方法来努力承认"无"可以归还是一个令人信服的理由.我不喜欢它被过度使用(甚至被滥用).例如,当看到人们将Optionals作为值放入地图时,我感到非常不安.为不存在/未映射的键映射null null是一个完善的范例......不需要让它变得更复杂...... (2认同)

Seb*_*ber 9

它看起来真的像MaybeHaskell 的Monad模式.

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

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


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

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);
Run Code Online (Sandbox Code Playgroud)

flatMap运营商是必不可少的,让一元操作,并允许轻松调用链所有返回可选结果.

想一想,如果你使用了map5次操作员,你会得到一个Optional<Optional<Optional<Optional<Optional<String>>>>>,而使用flatMap会给你Optional<String>

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


j2e*_*nue 6

使用它的一个很好的理由是它使你的空值非常有意义.您可以在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;
}
Run Code Online (Sandbox Code Playgroud)

}

现在让我们使用这个简单的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);   
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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


rai*_*tin 5

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

如果您约定始终对Optional可能的空对象进行约定,则可以对以下情况添加更多说明:

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

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

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

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

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

  • 根据上下文,包含 0 项的列表和不包含项的列表之间可能存在有意义的差异。 (2认同)