一尘不染

将Java 8的Optional与Stream :: flatMap一起使用

java

新的Java 8流框架和新朋友创建了一些非常简洁的Java代码,但是我遇到了一个看似简单的情况,很难做到简洁。

考虑一个List<Thing> things和方法Optional<Other> resolve(Thing thing)。我想将Things映射到Optionals并获得第一个Other。显而易见的解决方案是使用things.stream().flatMap(this::resolve).findFirst(),但是flatMap要求你返回一个流,并且Optional没有stream()方法(或者它是Collection或提供一种将其转换为或将其视为的方法Collection)。

我能想到的最好的方法是:

things.stream()
    .map(this::resolve)
    .filter(Optional::isPresent)
    .map(Optional::get)
    .findFirst();

但这对于一个很常见的案例来说似乎太漫长了。有人有更好的主意吗?


阅读 937

收藏
2020-03-13

共1个答案

一尘不染

Java 9

Optional.stream 已添加到JDK9。这使你无需任何帮助程序方法即可执行以下操作:

Optional<Other> result =
    things.stream()
          .map(this::resolve)
          .flatMap(Optional::stream)
          .findFirst();

Java 8

是的,这是API中的一个小漏洞,因为将Optional转换为长度为零或一的Stream有点不方便。你可以这样做:

Optional<Other> result =
    things.stream()
          .map(this::resolve)
          .flatMap(o -> o.isPresent() ? Stream.of(o.get()) : Stream.empty())
          .findFirst();

但是,在flatMap中使用三元运算符比较麻烦,因此最好编写一些辅助函数来完成此操作:

/**
 * Turns an Optional<T> into a Stream<T> of length zero or one depending upon
 * whether a value is present.
 */
static <T> Stream<T> streamopt(Optional<T> opt) {
    if (opt.isPresent())
        return Stream.of(opt.get());
    else
        return Stream.empty();
}

Optional<Other> result =
    things.stream()
          .flatMap(t -> streamopt(resolve(t)))
          .findFirst();

在这里,我内联了对resolve()的调用,而不是进行单独的map()操作,但这只是一个问题。

2020-03-13