【问题标题】:If nested Optional is empty, return another optional如果嵌套的 Optional 为空,则返回另一个 Optional
【发布时间】:2021-10-09 13:42:00
【问题描述】:

我的汽车模型看起来如何

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 说requered 类型是Engine,但我返回Engine 的可选类型。但是方法是可选的

【问题讨论】:

  • 只需在orElse 之前插入一个map(Optional::of)。它相当笨拙,但在更高版本的 java (cr.openjdk.java.net/~iris/se/16/latestSpec/api/java.base/java/…) 中引入了这方面的 API。
  • @CoronA 它有效。你能把它移到答案吗?谢谢
  • Optional 永远不会为空,为什么要返回它?很奇怪,在没有车甚至根本没有车的情况下返回Engine,只是要求接收器读取引擎的字符串以发现没有车。你的第二个 sn-p 更奇怪,因为它试图返回一个 new Car(…) 预期的引擎。

标签: java java-8 functional-programming optional


【解决方案1】:

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

在 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 是有意义的:

在第一个视图中,这种技术似乎非常复杂 - 事实上 - 仅对于这个示例,我更喜欢一个不返回可选的解决方案;

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

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
}

使用这种模式的另一个原因是我们不能假设该方法在最终返回之前没有返回真正的 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
}

【讨论】:

  • return Optional.of(car.flatMap(Car::getEngine).orElse(new Car("At the moment car don't have the engine"))); 即使使用新的or 也并不简单。但无论如何,整个方法都很奇怪。为不存在的值返回非空可选项的意义在哪里......
  • 当然你是对的,如果方法像现在这样简单,并且 API 不是公开的并且尚未使用。但是,如果我们仅将其视为一个示例,那么人们应该这样做有几个原因。我添加了一些解释性示例。
【解决方案2】:

错误是正确的,你传递了错误的类型:

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&lt;Car&gt;
  2. 我想Car::getEngineOptional&lt;Engine&gt;
  3. flatMap 取一个Function&lt;? super T, Optional&lt;U&gt;&gt;,其中TOptional 的绑定类型,这里:Car,U 是结果:这里Engine。它返回一个Optional&lt;U&gt;
  4. orElse(T) 返回一个已经计算好的结果。由于我们在 flatMap 之后,T 等于 Engine

注意:我链接到 Java 8 的 Javadoc。

所以orElse 中的期望值是Engine

你应该在flatMap之后停下来:

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

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

你应该扔:

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

请注意,我将结果从 Optional&lt;Engine&gt; 更改为 Engine

【讨论】:

  • 好的,在这种情况下,如果存在的话,oprional 会给我汽车引擎。而且,我会稍微改变一下这个逻辑:如果引擎不存在 -> 返回另一个可选的引擎。我没有看到,我在没有可选的模型中编写了引擎
  • 无需返回Optional&lt;Engine&gt;:只需返回Engine。在这一点上这是无用的,并且绝对不是Optional的正确用法。
猜你喜欢
  • 2019-06-12
  • 1970-01-01
  • 1970-01-01
  • 2022-01-06
  • 2021-02-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-14
相关资源
最近更新 更多