Java 有没有更清晰的方法来处理短期期权?

Java 有没有更清晰的方法来处理短期期权?,java,optional,Java,Optional,我喜欢Java中的可选。在一个简单的类中,它允许我清楚地识别返回类型和参数,这些类型和参数可能可用,也可能不可用 我要解决的一件事是,必须将其分配给一个短期变量,然后将该变量继承到后续的每个范围中 当使用如下选项时,我喜欢使用简单变量名opt: Optional<ThingA> opt = maybeGetThing(); if (opt.isPresent()) { ThingA usefulVariableName = opt.get();

我喜欢Java中的
可选
。在一个简单的类中,它允许我清楚地识别返回类型和参数,这些类型和参数可能可用,也可能不可用

我要解决的一件事是,必须将其分配给一个短期变量,然后将该变量继承到后续的每个范围中

当使用如下选项时,我喜欢使用简单变量名
opt

   Optional<ThingA> opt = maybeGetThing();

   if (opt.isPresent()) {
      ThingA usefulVariableName = opt.get();
      ...
   Optional<ThingA> optUsefulVariableName = maybeGetThing();

   if (optUsefulVariableName.isPresent()) {
      ThingA usefulVariableName = optUsefulVariableName.get();
      ...
虽然准确,但它极其冗长。我还尝试使用像
opt
I
这样的一次性名称,以表明这些名称实际上只是暂时的,不应超出其直接范围(即使它们将被继承)


更新:

我已经看到了使用
ifPresent()
的建议,但我不知道如何在可选项为空时也需要执行操作的情况下使用此选项:

void method() {
   Optional<ThingA> opt = maybeGetThing();

   if (!opt.isPresent()) {
      doSomethingOnlyHere();

      return;
   }

   if (opt.isPresent()) {
      ThingA usefulVariableName = opt.get();

      usefulVariableName.doA();
      usefulVariableName.doB();
      usefulVariableName.doC();

      // Duplicate local variable opt
      Optional<ThingB> opt = usefulVariableName.maybeAnotherThing();
   }
}

消除变量和调用
Optional#get
的最基本方法是使用
Optional.ifPresent
,如果Optional有值,它将调用函数

maybeGetThing().ifPresent(val -> {
    // do stuff with side effects here
});
使用Optional仍然是一种非常有限的方式,因为Optional的主要目的之一是促进函数式编程。如果你是一个初学者,这可能会让你有点不知所措,但是这个想法是让函数返回一些东西,而不是依赖于它的函数。依赖副作用的功能无法链接在一起,通常更难推理

从技术上讲,
Optional
是一种被称为函子的东西(来自范畴论)。它是一个围绕一个值(无论
T
是什么)的包装器,它允许通过一系列操作传递该值,对其进行操作,并将其传递给下一个操作,直到我们得到我们想要的,然后操作链以一个终端(即最终)操作结束。如果存在,终端操作可能返回未包装的值;如果不存在,则可能抛出或返回一些默认值

对于可选,如果值不存在,它将跳过任何后续操作

有一些常见的操作,如map、filter、flatMap(好的,这是一个Monad操作)和其他更特定于java的操作,如
Optional#orElse
Optional#orelsetrow

要重构示例代码,可以这样做

void method() {
   return maybeGetThing().flatMap(val -> {

       // eek side effects
       val.doA();
       val.doB();
       val.doC();

       return val.maybeAnotherThing();
   });  
}
flatMap
是一种将一种类型的可选项转换为另一种类型的可选项的方法。如果返回值不是可选的,您将使用map

您可以看到,为了命名lambda函数的参数,我们不再需要返回值的名称。lambda函数的作用域是限定的,因此如果您希望重用这些名称,就可以重用它们

我通常喜欢提供可运行的代码,所以这里有一个我的意思是可运行的人为例子

import java.util.Optional;

class DummyClass {

    private int val = 0;

    public void doA(){ val += 1; }

    public void doB(){ val += 2; }

    public void doC(){ val += 3; }

    public Optional<String> maybeAnotherThing(){
        return Optional.of(Integer.toString(val));
    }
}

public class UseOptional5 {   

    Optional<DummyClass> maybeGetThing(){
        return Optional.of(new DummyClass());
    }

    String method() {
        return maybeGetThing()
               // you can put other operations here
               .flatMap(val -> {

                    // eek side effects
                    val.doA();
                    val.doB();
                    val.doC();

                    return val.maybeAnotherThing();
                })
                // you can put other operations here too
                .orElseThrow(() -> new IllegalArgumentException("fail!!"));
    }    

    public static void main(String args[]) {

        UseOptional5 x = new UseOptional5();

        System.out.println(x.method());
    }
}
import java.util.Optional;
类DummyClass{
私有int val=0;
public void doA(){val+=1;}
public void doB(){val+=2;}
public void doC(){val+=3;}
公共可选内容可能是其他内容(){
返回可选的.of(Integer.toString(val));
}
}
公共类使用选项5{
可选的maybegetting(){
返回可选的.of(新的DummyClass());
}
字符串方法(){
返回maybegetting()
//您可以在这里进行其他操作
.flatMap(val->{
//eek副作用
val.doA();
val.doB();
val.doC();
return val.maybeAnotherThing();
})
//你也可以在这里进行其他操作
.orelsetrow(()->新的IllegalArgumentException(“失败!!”));
}    
公共静态void main(字符串参数[]){
UseOptional5 x=新的UseOptional5();
System.out.println(x.method());
}
}
自从Java 9以来,我愿意

void method() {
   maybeGetThing().ifPresentOrElse(
           usefulVariableName -> {
               usefulVariableName.doA();
               usefulVariableName.doB();
               usefulVariableName.doC();

               // No duplicate local variable opt
               Optional<ThingB> opt = usefulVariableName.maybeAnotherThing();
           },
           this::doSomethingOnlyHere
   );
}
void方法(){
maybegetting().ifpresentorese(
usefulVariableName->{
usefulVariableName.doA();
usefulVariableName.doB();
usefulVariableName.doC();
//无重复的局部变量opt
可选opt=usefulVariableName.maybeAnotherThing();
},
这里有什么
);
}

我的经验是,您很少需要或想要使用
isPresent
和/或
get
,它们是低级的。对于基本的东西,
ifPresent
(带
f
)和
ifPresetnOrElse
都可以。其他人认为
map
flatMap
也非常有用,这是正确的。

对于可选项和可选项中的内容,都需要变量的情况应该非常罕见。Optional的全部要点是,您可以使用
map
flatMap
等方法来操纵Optional中可能缺少的值。@PaulRooney非常有用的链接,谢谢。有人提出了一个很好的观点,但后来删除了它:使用
opt
是不好的。说出可选的东西<代码>可选foo=getFoo()<代码>如果(foo.isPresent())
读起来很好。当然,有时需要显式的
if/else
分支。当逻辑以保护返回序列的形式出现时,我经常在方法中将
Optional
转换为可空的
orNull()
(egads!heresy!):
void doSomething(){Foo-Foo=getFoo().orNull();if(Foo=null)返回;Bar=getBar().orNull();if(Bar==null)return;…
。我已经更新了我的问题。很抱歉给您更改了。我设计的示例没有反映更新中的情况。如果您可以使用java 9+,您可能会发现
可选的#ifpresentorese
很有用。请参阅。如果这是您现在的问题,那么它是提供的链接的副本。您也可以使用常规的If/else和避免多个lambda函数的噪音。
可选#ifPresentOrElse
不提供
import java.util.Optional;

class DummyClass {

    private int val = 0;

    public void doA(){ val += 1; }

    public void doB(){ val += 2; }

    public void doC(){ val += 3; }

    public Optional<String> maybeAnotherThing(){
        return Optional.of(Integer.toString(val));
    }
}

public class UseOptional5 {   

    Optional<DummyClass> maybeGetThing(){
        return Optional.of(new DummyClass());
    }

    String method() {
        return maybeGetThing()
               // you can put other operations here
               .flatMap(val -> {

                    // eek side effects
                    val.doA();
                    val.doB();
                    val.doC();

                    return val.maybeAnotherThing();
                })
                // you can put other operations here too
                .orElseThrow(() -> new IllegalArgumentException("fail!!"));
    }    

    public static void main(String args[]) {

        UseOptional5 x = new UseOptional5();

        System.out.println(x.method());
    }
}
void method() {
   maybeGetThing().ifPresentOrElse(
           usefulVariableName -> {
               usefulVariableName.doA();
               usefulVariableName.doB();
               usefulVariableName.doC();

               // No duplicate local variable opt
               Optional<ThingB> opt = usefulVariableName.maybeAnotherThing();
           },
           this::doSomethingOnlyHere
   );
}