Java Stream > 是否可以将 "orElseGet"内联到父流中?

标签 java java-8 java-stream option-type

我不确定如何准确地提出这个问题,所以请耐心等待...

1) 除了添加 null 之外,是否有更好(又名更“正确”)的方法来实例化可选元素的 Stream然后过滤掉 null 的?

Stream.of( ... ,
        person.likesRed() ? Color.RED : null)
        .filter(Objects::nonNull)
...

2) 其次,有没有办法将以下 orElseGet 函数“内联”到父 Stream/map?

.map(p -> ofNullable(p.getFavouriteColours()).orElseGet(fallbackToDefaultFavouriteColours))

完整的(人为的)例子:

import static java.util.Optional.ofNullable;

public Response getFavouriteColours(final String personId) {
    Person person = personService.findById(personId);

    Supplier<List<String>> fallbackToDefaultFavouriteColours = () ->
            Stream.of(
                    Color.BLUE,
                    Color.GREEN,
                    person.likesRed() ? Color.RED : null)
                    .filter(Objects::nonNull)
                    .map(Color::getName)
                    .collect(Collectors.toList());

    return ofNullable(person)
            .map(p -> ofNullable(p.getFavouriteColours()).orElseGet(fallbackToDefaultFavouriteColours))
            .map(Response::createSuccess)
            .orElse(Response::createNotFound);

}

最佳答案

更简洁的表达方式是

Stream.concat(Stream.of(Color.BLUE, Color.GREEN),
              person.likesRed()? Stream.of(Color.RED): Stream.empty())

这并不比您的原始表达式简单,但它不会产生插入某些内容只是为了事后将其过滤掉或更抽象地丢弃必须事后重建的已知信息的不良感觉。

甚至还有技术差异。上面的表达式创建了一个具有已知大小的流,可用于优化某些操作。相比之下,使用 filter 的变体只有一个估计大小,即过滤前的元素数量,但没有已知的确切大小。

通过不过度使用Optional可以大大简化周围的代码:

public Response getFavouriteColours(final String personId) {
    Person person = personService.findById(personId);
    if(person == null) return Response.createNotFound();

    List<String> favouriteColours = person.getFavouriteColours();
    if(favouriteColours == null)
        favouriteColours = Stream.concat(
                Stream.of(Color.BLUE, Color.GREEN),
                person.likesRed()? Stream.of(Color.RED): Stream.empty())
            .map(Color::getName)
            .collect(Collectors.toList());

    return Response.createSuccess(favouriteColours);
}

即使是 Stream 操作本身也不比这里的常规命令式代码简单:

public Response getFavouriteColours(final String personId) {
    Person person = personService.findById(personId);
    if(person==null) return Response.createNotFound();

    List<String> favouriteColours = person.getFavouriteColours();
    if(favouriteColours==null) {
        favouriteColours=new ArrayList<>();
        Collections.addAll(favouriteColours, Color.BLUE.getName(), Color.GREEN.getName());
        if(person.likesRed()) favouriteColours.add(Color.RED.getName());
    }
    return Response.createSuccess(favouriteColours);
}

尽管更复杂的示例可能会受益于 Stream API 的使用,而 Optional 的使用不太可能在更复杂的操作中变得更好。如果链中所有缺失的值或过滤器不匹配都应该在链的末端以相同的方式处理,则 Optional 操作链可以简化代码。但是,如果像您的示例(以及大多数现实生活中的场景)一样,每个缺失的值都应该得到不同的处理或单独报告,那么使用 Optional,尤其是 Optional 的嵌套使用,不会改进代码。

关于Java Stream > 是否可以将 "orElseGet"内联到父流中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41841410/

相关文章:

java - 分类器 JSONObject 没有“伴生对象”,因此必须在此处初始化

recursion - 使用 Java 8 Streams 求和树节点

java - 将一组 map 流式传输到单个 map 中

java - 在带有 appengine-maven-plugin 的 appengine 上的多模块 Maven Java 项目中部署期间跳过某些模块

java - 查找部分属性

java - 如何在检查是否存在 Java 8 Optional 时返回值?

java-8 - Java 8 forEach 无法解析为变量

java - 通过传入 char 变量打印列表中的所有字符串

java - 是否有更优雅的方法使用 Java 8 从列表中获取随机未使用的项目?

Java Applet 包装器规模输出