【问题标题】:How to directly map/expand object to stream?如何直接映射/扩展对象到流?
【发布时间】:2015-04-10 18:21:03
【问题描述】:

是否可以直接将对象展开成流?

我目前的做法是:

private BigDecimal getNodeScore(Optional<Node> node) {
    return node.map(Node::getBranches)
               .orElseGet(Collections::emptySet)
               .stream()
               .filter(Branch::isValid)
               .flatMap(Branch::getLeafs)
               .map(Leaf::getScore)
               .reduce(BigDecimal::ZERO, BigDecimal::add);
}

它工作得很好(是的,我知道它很丑......现在)但只是讨厌使用 orElseGet 和 steam 从 Optional 过渡到 Stream 所以我想知道是否有任何方法可以将 Optional 扩展到 Stream ?

我需要的是这样的:

private BigDecimal getNodeScore(Optional<Node> node) {
    return node.mapToStream(Node::getBranches)  // <-- Want something similar
               .filter(Branch::isValid)
               .flatMap(Branch::getLeafs)
               .map(Leaf::getScore)
               .reduce(BigDecimal::ZERO, BigDecimal::add);
}

我知道我总是可以创建一个辅助函数并将第一个调用包装成如下内容:

optionalToStream(node.map(Node::getBranches))

但仍然想知道是否有更优雅的方式。

【问题讨论】:

    标签: java dictionary tree java-8 reduce


    【解决方案1】:

    它工作得很好(是的,我知道它很丑......现在)但只是讨厌使用 orElseGet 和 steam 从 Optional 过渡到 Stream

    说实话,我不认为你的方法是丑陋的。您仍然可以使用isPresent() 来测试可选项是否包含值。

    private BigDecimal getNodeScore(Optional<Node> node) {
        return node.isPresent() ? node.get()
                                      .getBranch()
                                      .stream()
                                      .filter(Branch::isValid)
                                      .flatMap(Branch::getLeafs)
                                      .map(Leaf::getScore)
                                      .reduce(BigDecimal.ZERO, BigDecimal::add) : BigDecimal.ZERO;
    }
    

    如果您认为情况更糟,另一种解决方法是在您的 Node 类中提供一个直接返回 Stream&lt;Branch&gt; 的方法。

    private BigDecimal getNodeScore(Optional<Node> node) {
        return node.map(Node::getBranchesStream)
                   .orElseGet(Stream::empty)
                   .filter(Branch::isValid)
                   .flatMap(Branch::getLeafs)
                   .map(Leaf::getScore)
                   .reduce(BigDecimal.ZERO, BigDecimal::add);
    }
    

    是否可以直接将对象展开成流?

    是的,有Stream.of 用于此目的,但您不需要它,因为getBranch 返回Set,因此您只需调用stream() 即可获得结果流。

    【讨论】:

      【解决方案2】:

      您始终可以使用optional.map(Stream::of).orElseGet(Stream::empty)Optional 转换为由零个或一个元素组成的Stream。如果流的项可以提供Stream,您确实想要处理,您可以使用flatMap 将流的项替换为评估的结果流,或者如果Optional 为空,则保留为空流。

      例如

      Optional<Node> optional=Optional.empty();
      optional.map(Stream::of).orElseGet(Stream::empty)
         .map(Node::getBranches).flatMap(Collection::stream)
      // follow-up operations
      

      optional.map(Stream::of).orElse(Stream.empty())
         .flatMap(node -> node.getBranches().stream())
      // follow-up operations
      

      但在这种特殊情况下,您也可以将其融合到一个操作中

      optional.map(node -> node.getBranches().stream()).orElse(Stream.empty())
      // follow-up operations
      

      (但我认为在优化之前了解一般模式是值得的……)

      【讨论】:

      • 该死,Collection::stream 正是我需要的,我刚刚做了 node.map(Node::getBranches).map(Collection::stream).orElseGet(Stream::empty).filter (Branch::isValid)...而且效果很好。谢谢:)
      • 顺便说一下,刚刚做了一个粗略的测试,看看“.map(node -> node.getbranches().stream())”是否会比映射两次更快。在大约 10000 深和 1000 宽的树上运行 1000 次,平均只有 1 毫秒的优势。不过,我觉得差异太微不足道,甚至不在乎那 1 毫秒,如果我决定在某个时候优化代码,我总是可以尝试 parallelStream 甚至将它完全移植到 C 中。 ;)
      • 如果存在显着差异,我感到很惊讶,因为所有变体基本上都在做相同的事情,并且不同的符号不应该混淆 HotSpot 优化器。毕竟,您应该使用您认为更具可读性的内容……
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-12-12
      • 1970-01-01
      • 1970-01-01
      • 2016-06-27
      • 1970-01-01
      • 2018-04-14
      • 2019-07-16
      相关资源
      最近更新 更多