【问题标题】:How could collateral effects be managed in Java8 streams如何在 Java8 流中管理附带影响
【发布时间】:2015-02-19 11:32:58
【问题描述】:

我知道 Java8 中的 Streams 只能收集一次(如在 forEach() 终止中),但我想知道我们是否可以设法“挖掘”到位于过滤和映射任务链中间的流产生一些附带效应。

本质上,“点击”就像执行 forEach() 但在管道的那个点返回 Stream。

我会这样使用它:

List<User> createAndPersistRandomUsers(int count) {
  return IntStream.range(0, count)
    .boxed() // returns Stream<Integer>
    .map(UserBuilder::random) // returns Stream<User>
    .tap(userRepo::persist) // Collateral persist of user, returns Stream<User>
    .collect(toList()); // returns List<User>
}

有什么想法吗?

【问题讨论】:

    标签: java functional-programming java-8 java-stream


    【解决方案1】:

    我能想到的最接近你想要的东西是peek

    Stream peek(消费者操作)

    返回一个由该流的元素组成的流, 另外对每个元素执行提供的操作 元素从结果流中消耗。

    这是一个中间操作。

    它允许您在 Stream 被消费时对 Stream 的元素执行操作。

    List<User> createAndPersistRandomUsers(int count) {
      return IntStream.range(0, count)
        .boxed() // returns Stream<Integer>
        .map(UserBuilder::random) // returns Stream<User>
        .peek(userRepo::persist) // Collateral persist of user, returns Stream<User>
        .collect(toList()); // returns List<User>
    }
    

    【讨论】:

    • 值得注意的是,这不是forEach 类似问题所要求的操作,因为peek 只会处理项目,因为它们恰好被处理以适应终端操作。例如。如果终端操作是findAny,则您可以确定peek 将看到的唯一项目是匹配项目,所有其他项目都可能被跳过。这甚至可能以依赖于实现的方式发生变化,例如当前实现在终端操作为count时处理所有项目,如果底层Spliterator具有SIZED特性,未来版本可能会跳过整个处理。
    • @Holger 我同意,但是对于这个问题中的用例(终端操作处理流的所有元素),我认为它会产生预期的行为(即列表中返回的每个用户也将作为副作用持久化。当然,这样做比首先生成列表然后持久化所有用户没有真正的优势。
    • 对,它在这里有效,这就是为什么我只是说“值得注意”,因为我怀疑否则一旦 OP 更改终端操作,我们就会有关于 SO 的后续问题。
    • 谢谢!你的回答很有趣:) 不过,@Holger 指出的问题值得研究。我将问题标记为已回答
    猜你喜欢
    • 2017-04-30
    • 2017-01-19
    • 2019-10-15
    • 2015-05-26
    • 1970-01-01
    • 2019-07-19
    • 2023-03-07
    • 2017-03-29
    • 1970-01-01
    相关资源
    最近更新 更多