【问题标题】:Is there workaround to "return" stream from forEach method?是否有从 forEach 方法“返回”流的解决方法?
【发布时间】:2016-11-23 02:49:51
【问题描述】:

说有一个集合需要先修改再过滤:

Collection<MyObject> collection = ...
Stream<MyObject> dummyVariable = collection.stream();
dummyVariable.forEach(i -> i.callModifyingFunc(args));
return dummyVariable.filter(i -> i.isNeeded);

因为 forEach 具有void 返回类型,所以没有dummyVariable 就无法编写代码。是否有任何解决方法可以在一个链中编写所有内容:

Collection<MyObject> collection = ...
return Stream<MyObject> dummyVariable = collection.stream().forEach(i -> i.callModifyingFunc(args)).filter(i -> i.isNeeded);

【问题讨论】:

标签: foreach java-8 java-stream


【解决方案1】:

只需使用 map 而不是 forEach 来链接管道操作:

collection.stream()
          .map(i -> i.callModifyingFunc(args))
          .filter(i -> i.isNeeded);

【讨论】:

  • 仅当您想放松对哪些对象被修改和哪些不被修改的任何控制时......
【解决方案2】:

如果您将Stream 返回给调用者,则您无法控制最终由调用者链接的终端操作。终端操作可能会处理所有元素,但也可能是短路的,甚至可能是调用者在根本没有应用终端操作的情况下放弃了流。

如果修改只是为了记录一个元素是否被处理,peek是正确的选择。

但是,如果您想在任何一种情况下对每个元素都应用修改,只需直接进行:

Collection<MyObject> collection = ...
collection.forEach(i -> i.callModifyingFunc(args));
return collection.stream().filter(i -> i.isNeeded);

如果要确保只在调用者开始终端操作时进行修改,那就有点复杂了:

Collection<MyObject> collection = ...
Spliterator<MyObject> sp = collection.spliterator();
return StreamSupport.stream(() -> {
        collection.forEach(i -> i.callModifyingFunc(args));
        return sp;
    }, sp.characteristics(), false)
    .filter(i -> i.isNeeded);

这将在 Stream 处理开始之前执行所有元素的修改,即在执行终端操作之前。

但是您应该重新考虑您的要求。在流处理之前必须修改所有元素听起来很可疑。如果两个客户端获取一个流会发生什么?

【讨论】:

    猜你喜欢
    • 2021-04-15
    • 2014-12-22
    • 2017-08-14
    • 2021-12-30
    • 2023-04-06
    • 1970-01-01
    • 1970-01-01
    • 2019-03-30
    相关资源
    最近更新 更多