可选orElse Java中的可选项

问题

我一直在使用newOptional type in Java 8,而且我遇到了一个似乎是功能上不支持的常见操作:"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();
}

我很好奇是否存在这样一种方法不存在的原因,如果我只是以一种无意的方式使用Optional,以及人们如何处理这种情况。

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

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


#1 热门回答(68 赞)

这是JDK 9的一部分,形式为887748299,版本为Supplier<Optional<T>>。那么你的例子就是:

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

有关详细信息,请参见the Javadocthis postI。


#2 热门回答(51 赞)

鉴于当前的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)就足够了。

由于对流的延迟评估,如果前面的服务返回非emptyOptional,则不会调用任何服务。


#3 热门回答(27 赞)

它不漂亮,但这将工作:

return serviceA(args)
  .map(Optional::of).orElseGet(() -> serviceB(args))
  .map(Optional::of).orElseGet(() -> serviceC(args))
  .map(Optional::of).orElseGet(() -> serviceD(args));

.map(func).orElseGet(sup)是一个非常方便的模式,可用于Optional。这意味着"如果这个Optional包含值v,请给我func(v),否则给我sup.get()"。

在这种情况下,我们致电serviceA(args)并获得Optional<Result>。如果thatOptional包含valuev,我们想要获得Optional.of(v),但如果它是空的,我们想得到serviceB(args)。用更多替代品冲洗重复。

这种模式的其他用途是

  • .map(Stream :: of)。orElseGet(Stream :: empty)
  • .map(Collections :: singleton).orElseGet(Collections :: emptySet)