Java 什么';这是番石榴的要点;s选修课

Java 什么';这是番石榴的要点;s选修课,java,generics,guava,Java,Generics,Guava,我最近读过这篇文章,看到人们使用这个类,但在几乎所有情况下,使用null也同样有效——如果不是更直观的话。有人能提供一个具体的例子,说明Optional可以实现null无法实现的功能,或者以更简洁的方式实现?我能想到的唯一一件事是将它与不接受null键的Maps一起使用,但即使是这样,也可以使用null值的侧“映射”来完成。有谁能给我提供一个更有说服力的论点吗?谢谢。这里是番石榴队的成员 null最大的缺点可能是它在任何给定上下文中的含义都不明显:它没有说明性的名称。null表示“此参数没有值”

我最近读过这篇文章,看到人们使用这个类,但在几乎所有情况下,使用
null
也同样有效——如果不是更直观的话。有人能提供一个具体的例子,说明
Optional
可以实现
null
无法实现的功能,或者以更简洁的方式实现?我能想到的唯一一件事是将它与不接受
null
键的
Maps
一起使用,但即使是这样,也可以使用null值的侧“映射”来完成。有谁能给我提供一个更有说服力的论点吗?谢谢。

这里是番石榴队的成员

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

但是我想说,
可选的最大优势不在于可读性:优势在于它的防白痴性。如果你想让你的程序编译的话,它会迫使你积极地考虑不存在的情况,因为你必须积极地打开
Optional
并解决这个问题。Null使简单地忘记事情变得令人不安,尽管FindBugs有帮助,但我认为它不能很好地解决这个问题。当您返回可能“存在”或可能不“存在”的值时,这一点尤其重要。您(和其他人)更可能忘记
other。方法(a,b)
可能返回
null
值,而不是在实现
other.method
时忘记
a
可能是
null
。返回
Optional
使调用方无法忘记该情况,因为他们必须自己打开对象

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

(顺便说一句,这完全是从讨论中抄袭出来的。)

它看起来真的像哈斯克尔的单子模式

你应该阅读以下维基百科:

阅读其中讨论了番石榴作为单子的可选成分:


编辑: 在Java8中,有一个内置的可选项,它具有一元运算符,如
flatMap
。这一直是一个有争议的话题,但最终得到了实施

public可选tryfindSimular(字符串s)/。。。
可选错误=opt.map(this::tryfindSimular);
可选相似=opt.flatMap(this::tryFindSimular);
flatMap
运算符对于允许一元操作非常重要,并且允许轻松链接所有返回可选结果的调用

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


由于Java8,我宁愿不使用功能较弱的Guava的Optional。

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

如果将约定设置为对可能的空对象始终具有
可选
,则会对以下情况添加更多说明:

  • 可选maxPrime(可选自,可选至)

    此处的合同明确规定有可能不返回结果,但也表明它将在
    from
    to
    不存在的情况下工作

  • 可选最大素数(可选从、整数到)

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


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

    使用它的一个很好的理由是它使null非常有意义。不必返回可能意味着许多事情(如错误、失败或空等)的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);   
        }
    }
    
    public可选getPersonDetailstWithOptional(){
    PersonDetails details=null;/*此人的详细信息为空,但对调用者来说这没有意义,
    让返回值更有意义*/
    如果(详细信息==null){
    //在此处返回缺席,来电者可以检查缺席情况以表示不存在详细信息
    返回可选的。缺席();
    }否则{
    //否则返回用番石榴“可选”包装的详细信息
    返回可选。的(详细信息);
    }
    }
    
    现在,让我们避免使用null,并使用可选项进行检查,这样它才有意义

    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());
    }
    
    public void checkUsingOptional(){
    可选详细信息=getPersonDetailstWithOptional();
    /*以下条件检查人员详细信息是否存在(注意,我们不检查人员详细信息是否为空,
    我们使用了一些更有意义的东西。番石榴(可选)强制实现)*/
    if(details.isPresent()){
    PersonDetails details=details.get();
    //继续进一步处理
    logger.info(详情);
    }否则{
    //无所事事
    logger.info
    
    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());
    }