Java 8可选的orElse可选
我一直在使用Java 8中的新的可选types ,并且遇到了一个看起来像一个常见的操作,但是在function上不受支持:“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); }
这种模式有很多种forms,但是它归结为想要一个可选的“orElse”,它带有一个产生一个新的可选的函数,只有当前函数不存在时才被调用。
它的实现看起来像这样:
public Optional<T> orElse(Supplier<Optional<? extends T>> otherSupplier) { return value != null ? this : other.get(); }
我很好奇,如果有这样的一个方法不存在的原因,如果我只是用一个意想不到的方式使用可选,以及人们提出了什么其他方式来处理这种情况。
我应该说,我认为涉及自定义实用程序类/方法的解决scheme并不优雅,因为使用我的代码的人不一定知道它们存在。
另外,如果有人知道,这个方法是否会包含在JDK 9中,我可以在哪里提出这样一个方法? 这似乎是API的一个非常明显的遗漏给我。
这是or
forms的JDK 9的一部分,它采用Supplier<Optional<T>>
。 你的例子将是:
return serviceA(args) .or(() -> serviceB(args)) .or(() -> serviceC(args));
有关详细信息,请参阅(初步)Javadoc或我写的这篇文章 。
鉴于目前的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)
就足够了。
由于stream的延迟评估,如果前面的服务返回了非空的可Optional
,将不会调用服务。
这不是很好,但这将工作:
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>
。 如果这个Optional
包含值v
,我们想获得Optional.of(v)
,但是如果它是空的,我们想获得serviceB(args)
。 冲洗 – 重复更多的select。
这种模式的其他用途是
-
.map(Stream::of).orElseGet(Stream::empty)
-
.map(Collections::singleton).orElseGet(Collections::emptySet)
也许这就是你所追求的: 从一个可选的或另一个可以获得价值
否则,你可能想看看Optional.orElseGet
。 下面是我认为你之后的一个例子:
result = Optional.ofNullable(serviceA().orElseGet( () -> serviceB().orElseGet( () -> serviceC().orElse(null))));
这看起来非常适合模式匹配,而更传统的带有Some和None实现的Option接口(比如Javaslang , FunctionalJava中的 )或者Cyclops中的一个懒惰的Maybe实现。我是这个库的作者。
与独眼巨人反应,你也可以使用JDKtypes的结构模式匹配 。 对于可选,您可以通过访客模式匹配当前和不存在的案例。 它会看起来像这样 –
import static com.aol.cyclops.Matchables.optional; optional(serviceA(args)).visit(some -> some , () -> optional(serviceB(args)).visit(some -> some, () -> serviceC(args)));