如果 nested Optional 为空,return 另一个可选

If nested Optional is empty, return another optional

我的汽车模型看起来如何

class Car {
   // some fields here
   Optional<Engine> engine;
}

我如何通过几步完成:

    public Optional<Engine> checkEngine (Optional<Car> car) {
        Optional<Engine> engine = car
                .flatMap(Car::getEngine)
        if (engine.isPresent()) {
            return engine;
        }
        return Optional.of(new Engine("At the moment car don't have the engine"));
    }

我想在 1 个可选表达式中完成:

    public Optional<Engine> checkEngine (Optional<Car> car) {
        return car
                .flatMap(Car::getEngine)
                .orElse(Optional.of(new Car("At the moment car don't have the engine")));
    }

但它不起作用,intelij idea 说请求的类型是 Engine,但我返回可选的 Engine。但是方法是可选的

错误正确,您传递的类型错误:

public Optional<Engine> checkEngine (Optional<Car> car) {
    return car
            .flatMap(Car::getEngine)
            .orElse(Optional.of(new Car("At the moment car don't have the engine")));
}
  1. carOptional<Car>
  2. 我想 Car::getEngineOptional<Engine>
  3. flatMap 取一个 Function<? super T, Optional<U>>,其中 TOptional 的绑定类型,此处:Car,结果 U:此处 Engine。它 return 是 Optional<U>.
  4. orElse(T) return 一个已经计算出来的结果。由于我们在 flatMap 之后,T 等于 Engine.

注意: 我链接到 Javadoc of Java 8.

所以 orElse 中的期望值是 Engine.

你应该在 flatMap:

之后停止
public Optional<Engine> checkEngine (Optional<Car> car) {
    return car.flatMap(Car::getEngine);
}

而且我认为您不应该像您尝试做的那样return“无效”Engine:您将永远无法区分引擎丢失的情况和引擎丢失的情况它存在的地方。

你应该扔:

public Engine checkEngine (Optional<Car> car) {
    return car.flatMap(Car::getEngine)
              .orElseThrow(() -> new IllegalStateException("no engine"));
}

请注意,我将结果从 Optional<Engine> 更改为 Engine

在 8 (https://cr.openjdk.java.net/~iris/se/16/latestSpec/api/java.base/java/util/Optional.html#or(java.util.function.Supplier)) 之后的 Java 版本中引入了将两个可选结果加入可选结果的可能性。

在 Java 8 中你必须解决这个问题,例如

public Optional<Engine> checkEngine (Optional<Car> car) {
  return car
    .flatMap(Car::getEngine)
    .map(Optional::of)
    .orElse(Optional.of(new Engine("At the moment car doesn't have the engine")));
}

使用 Java 9 or() 它看起来像:

public Optional<Engine> checkEngine (Optional<Car> car) {
  return car
    .flatMap(Car::getEngine)
    .or(() -> Optional.of(new Engine("At the moment car don't have the engine")));
}

详细说明为什么使用 or 有意义:

这种技术乍一看似乎非常复杂 - 事实上 - 仅对于此示例,我更喜欢没有 return 可选的解决方案;

然而这种技术一般来说并不是没有意义的,如果我们有一组回退函数,每个 returning 一个可选的,例如

public Optional<Engine> checkEngine (Optional<Car> car) {
  return car
    .flatMap(Car::getEngine)
    .or(this::fallback1) //only call this expensive method as fallback
    .or(this::fallback2); //only call this expensive method as fallback
}

public Optional<Engine> fallback1() {
  //some code computing a fallback, but can fail and then returns empty
}

public Optional<Engine> fallback2() {
  //some code computing a fallback, but can fail and then returns empty
}

使用这种模式的另一个原因是我们不能假设该方法在最终 return 之前没有 return 真正的 Optionals,例如

public Optional<Engine> checkEngine (Optional<Car> car) {
  if (isInvalid()) {
    return Optional.empty(); // this is a true error
  }
  // other code
  return car
    .flatMap(Car::getEngine)
    .or(() -> Optional.of(new Engine("At the moment car don't have the engine"))); // it is not an error if car is empty, because there is a valid default
}