当前位置: 首页 > 知识库问答 >
问题:

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

岳涵煦
2023-03-14

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

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

当使用这样的选项时,我喜欢使用简单的变量名称opts

   Optional<ThingA> opt = maybeGetThing();

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

但当我需要在这个范围内使用变量名时。。。

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

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

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

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

我可以使用诸如optAoptB之类的东西。但是我想知道是否有另一种方法可以编写这段代码,而不必枚举我的临时变量。这有点像懒惰的变量名,比如aaaaaaaaaabbb或其他东西。

我不想像这样明确地命名我所有的选项:

   Optional<ThingA> optUsefulVariableName = maybeGetThing();

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

虽然准确,但却极其冗长。我还尝试使用像optI这样的一次性名称,以表明这些名称实际上只是暂时的,不应超出其直接范围(即使它们将被继承)。

更新:

我已经看到了使用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();
   }
}

当我尝试使用ifPresent()进行重构时:

void method() {
   // Doesn't handle instance where I need side effects on an empty optional
   maybeGetThing().ifPresent(usefulVariableName -> {
      ...
   }
}

共有2个答案

陈誉
2023-03-14

从Java9开始

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

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

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

沈琨
2023-03-14

消除变量和调用Optional#get的最基本方法是使用Optional。ifPresent,如果可选项有值,则调用函数。

maybeGetThing().ifPresent(val -> {
    // do stuff with side effects here
});

使用Optional仍然是一种非常有限的方式,因为Optional的主要目的之一是促进函数式编程。如果你是个初学者,这可能会让你有点不知所措,但我们的想法是让函数返回一些东西,而不是依赖于副作用的函数。依赖于副作用的功能无法链接在一起,通常更难推理。

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

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

有一些常见的操作,比如map、filter、flatMap(好的,这是一个Monad操作)和其他更具体的java操作,比如Optional#orElseOptional#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());
    }
}
 类似资料:
  • 问题内容: 有没有很好的方法来获取下一个星期三的日期?也就是说,如果今天是星期二,我想获取本周星期三的日期;如果今天是星期三,我想知道下星期三的日期;如果今天是星期四,我想获取下周的星期三日期。 谢谢。 问题答案: 基本算法如下: 获取当前日期 取得星期几 与周三找到不同 如果差异不是正数,则加7(即坚持下一个到来/将来的日期) 增加差异 这是一个片段,展示了如何使用: 相对于我现在的位置,上述代

  • 我的问题是如何从多个(或分片)TFR记录中获取批输入。我读过这个例子https://github.com/tensorflow/models/blob/master/inception/inception/image_processing.py#L410.以培训集为例,基本管道是:(1)首先生成一系列TF记录(例如,,,…),(2) 从这些文件名生成一个列表,并将它们输入到获取队列,(3)同时生成

  • 除了把它们全部输入外,还有没有更好的方法在字符串中列出它们?

  • 我想使用以下循环创建一个新列。表中只有“open”和“start”列。我想创建一个新列“startopen”,如果“start”等于1,那么“startopen”等于“open”。否则,“startopen”等于此新创建列上方行中的任何“startopen”。目前,我能够通过以下方式实现这一点: 这有效,但对于大型数据集来说非常慢。是否有任何内置函数可以更快地完成此操作?

  • 我在github的sping-hateoas存储库中也看到了一个类似的问题,但答案是在stackoverflow中提问。 我在项目中使用spring hateoas PagedResources来返回APIendpoint的响应。我现在有了一个APIendpoint,其中的计数信息将不可用,因此我使用的是一个切片,而不是一个页面。但是,在构建响应时,我没有找到SlicedResources,只有P

  • 我正试图将一个阻塞消费者集成为Reactor铝-SR1中的助焊剂订户。我想使用一个并行调度器,并发地执行阻塞操作。 我实现了一个主类来描述我意图: