简体   繁体   English

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

[英]Is there a clearer way to deal with short-lived optionals?

I love Optional in Java.我喜欢 Java 中的Optional It has, in one simple class, allowed me to clearly identify return types and arguments which may or may not be available.在一个简单的类中,它允许我清楚地识别可能可用或可能不可用的返回类型和参数。

One thing that I struggle with is the necessity of assigning it to a short-lived variable which is then inherited into every subsequent scope.我挣扎的一件事是必须将它分配给一个短期变量,然后将其继承到每个后续范围。

I like to use the simple variable name opt when using optionals like this:在使用这样的选项时,我喜欢使用简单的变量名opt

   Optional<ThingA> opt = maybeGetThing();

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

But when I then need a variable name to use in this scope...但是当我需要一个变量名在这个范围内使用时......

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

I can use things like optA and optB and so on.我可以使用optAoptB类的东西。 But I wonder if there is another way to write this code without having to enumerate my temporary variables.但是我想知道是否有另一种方法可以编写此代码而不必枚举我的临时变量。 This just smacks of lazy variable names like a aaaa aaaaaabbb or something.这只是像aaaa aaaaaabbb类的懒惰变量名称a aaaaaabbb

I don't want to name all of my optionals explicitly like this:我不想像这样明确地命名我的所有选项:

   Optional<ThingA> optUsefulVariableName = maybeGetThing();

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

While accurate, it is extremely verbose.虽然准确,但非常冗长。 I also try to use throwaway names like opt and i to indicate that these are in fact only temporary and should serve no purpose beyond their immediate scope (even though they will be inherited).我还尝试使用像opti这样的一次性名称来表明这些名称实际上只是暂时的,不应超出其直接范围(即使它们将被继承)。


UPDATE:更新:

I have seen suggestions for using ifPresent() but I don't see how I can use this for instances where I also need to perform an action if the optional is empty:我已经看到了使用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();
   }
}

When I try to refactor with ifPresent() :当我尝试使用ifPresent()进行重构时:

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

The most basic way to eliminate the variable and the need to call Optional#get is to use Optional.ifPresent which calls a function if the Optional has a value.消除变量和需要调用Optional#get最基本方法是使用Optional.ifPresent ,如果 Optional 有值,它会调用函数。

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

This is still quite a limited way to use Optional, as one of Optionals key purposes is to facilitate programming in a functional style.这仍然是使用 Optional 的一种非常有限的方式,因为 Optional 的一个关键目的是促进以函数式风格进行编程。 If you are a beginner this may be a little lost on you, but the idea is to have functions that return something and not functions that rely on side effects .如果您是初学者,这对您来说可能会有点迷茫,但我们的想法是让函数返回一些东西,而不是依赖于副作用的函数。 Functions relying on side effects cannot be chained together and are generally harder to reason about.依赖副作用的函数不能链接在一起,而且通常更难推理。

Technically Optional is something called a Functor (from category theory).技术上Optional是称为函子的东西(来自范畴论)。 It is a wrapper around a value (Whatever T is) and it allows the value to be passed through a series of operations to operate on it and pass it to the next operation until we have what we want, then the chain of operations ends with a terminal (ie final) operation.它是一个值(无论T是什么)的包装器,它允许该值通过一系列操作对其进行操作并将其传递给下一个操作,直到我们得到我们想要的结果,然后操作链以一个终端(即最终)操作。 The terminal operation may return the unwrapped value if it exists or it could throw or return some default value if it doesn't.如果存在,终端操作可能会返回解包的值,如果不存在,它可能会抛出或返回一些默认值。

For Optional it will skip any subsequent operations if the value becomes not present.对于 Optional,如果该值不存在,它将跳过任何后续操作。

There are common operations like map, filter, flatMap (ok that's a Monad operation) and other more java specific operations like Optional#orElse and Optional#orElseThrow .有一些常见的操作,如 map、filter、flatMap(好吧,这是一个 Monad 操作)和其他更多的 Java 特定操作,如Optional#orElseOptional#orElseThrow

To refactor your example code you could do this.要重构您的示例代码,您可以这样做。

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

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

       return val.maybeAnotherThing();
   });  
}

flatMap is a way of converting an Optional of one type to an Optional of another type. flatMap是一种将一种类型的 Optional 转换为另一种类型的 Optional 的方法。 If the return value weren't Optional you would use map.如果返回值不是 Optional,您将使用 map。

You can see we have eliminated the need for names of return values in favour of naming the parameters of lambda functions.您可以看到我们已经消除了对返回值名称的需求,而有利于命名 lambda 函数的参数。 The lambda functions are scoped so you can reuse the names if that's what you want to. lambda 函数是有作用域的,因此您可以根据需要重用名称。

I generally like to provide runnable code, so here is a contrived example of what I mean which is runnable.我通常喜欢提供可运行的代码,所以这里有一个人为的例子来说明我的意思是可运行的。

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

Since Java 9 I'd do从 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
   );
}

My rule of thumb is you seldom need or want to use isPresent and/or get , they are low-level.我的经验法则是你很少需要或想要使用isPresent和/或get ,它们是低级的。 For basic things ifPresent (with f ) and ifPresetnOrElse are fine.对于基本的东西ifPresent (带f )和ifPresetnOrElse很好。 Others are correct that map and flatMap are very useful too.其他人认为mapflatMap也非常有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM