Java 中的 Optional orElse Optional

2022-08-31 07:31:02

我一直在Java 8中使用新的Optant类型,并且我遇到了一个似乎在功能上不受支持的常见操作:“orElseOptional”

请考虑以下模式:

Optional<Result> resultFromServiceA = serviceA(args);
if (resultFromServiceA.isPresent) return result;
else {
    Optional<Result> resultFromServiceB = serviceB(args);
    if (resultFromServiceB.isPresent) return resultFromServiceB;
    else return serviceC(args);
}

这种模式有很多种形式,但它归结为在一个可选的上想要一个“orElse”,该可选模式采用一个产生新可选的函数,仅当当前可选不存在时才调用。

它的实现将如下所示:

public Optional<T> orElse(Supplier<Optional<? extends T>> otherSupplier) {
    return value != null ? this : other.get();
}

我很好奇这种方法是否存在的原因,如果我只是以一种意想不到的方式使用Anfedsable,以及人们想出了什么其他方法来处理这种情况。

我应该说,我认为涉及自定义实用程序类/方法的解决方案并不优雅,因为使用我的代码的人不一定知道它们的存在。

另外,如果有人知道,这样的方法是否会包含在JDK 9中,我可以在哪里提出这样的方法?对我来说,这似乎是API的一个非常明显的遗漏。


答案 1

这是 JDK 9 的一部分,形式为 ,它采用 .然后,您的示例将是:orSupplier<Optional<T>>

return serviceA(args)
    .or(() -> serviceB(args))
    .or(() -> serviceC(args));

有关详细信息,请参阅Javadoc或我写的这篇文章


答案 2

鉴于当前的API,最干净的“尝试服务”方法是:

Optional<Result> o = Stream.<Supplier<Optional<Result>>>of(
    ()->serviceA(args), 
    ()->serviceB(args), 
    ()->serviceC(args), 
    ()->serviceD(args))
.map(Supplier::get)
.filter(Optional::isPresent)
.map(Optional::get)
.findFirst();

重要的方面不是你必须编写一次的(恒定的)操作链,而是添加另一个服务(或修改一般服务列表)的难易程度。在这里,添加或删除单个就足够了。()->serviceX(args)

由于流的延迟求值,如果前面的服务返回非空 ,则不会调用任何服务。Optional


从 Java 9 开始,您可以将代码简化为

Optional<Result> o = Stream.<Supplier<Optional<Result>>>of(
    ()->serviceA(args), 
    ()->serviceB(args), 
    ()->serviceC(args), 
    ()->serviceD(args))
.flatMap(s -> s.get().stream())
.findFirst();

尽管这个答案已经包含了JDK 9的更简单的方法。

JDK 16 提供了替代方案

Optional<Result> o = Stream.<Supplier<Optional<Result>>>of(
    ()->serviceA(args), 
    ()->serviceB(args), 
    ()->serviceC(args), 
    ()->serviceD(args))
.<Result>mapMulti((s,c) -> s.get().ifPresent(c))
.findFirst();

尽管此方法可能更方便,因为服务方法接受 a 而不是返回 .ConsumerSupplier


推荐