新的Java8流框架和friends提供了一些非常简洁的Java代码,但我遇到了一个看似简单的情况,很难做到简洁.

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

我能想到的最好结果是:

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

但对于一个非常常见的 case 来说,这似乎太冗长了.有谁有更好的主意吗?

推荐答案

Java 9

Optional.stream已添加到JDK 9中.这使您无需任何助手方法即可执行以下操作:

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

Java 8

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

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()操作,但这是一个喜好问题.

Java相关问答推荐

如何为具有多对多关系的实体的给定SQL查询构建JPA规范?

Java 21虚拟线程会解决转向react 式单线程框架的主要原因吗?

最小拓Flutter 排序的时间复杂度是多少?

参数值[...]与预期类型java.util.Date不匹配

Apache POI:使用反射获取zoom 级别

上下文初始化期间遇到异常-使用Java配置配置HibernateTemplate Bean时

Bean定义不是从Spring ApplationConext.xml文件加载的

在Eclipse中数组的可空性

基于接口的投影、原生查询和枚举

匹配一组字符或另一组字符

如果按钮符合某些期望,如何修改它的文本?

为什么Collectors.toList()不能保证易变性

是否在settings.xml中使用条件Maven镜像?

将ByteBuffer异步写入InputStream或Channel或类似对象

如何在盒子的顶部和底部创建两张不同图片(大小相同)的盒子?

如何生成指定范围内的11位序列号?

JavaFX:无论何时显示应用程序,如何更改组件/ node 位置?

如何对存储为字符串的大数字数组进行排序?

双对象供应商

如何使用Jackson读取以方括号开头的JSON?