我有一个 Stream,它以
peek()
方法进行所有处理。我不需要流中的任何结果,但我需要终端操作才能进行处理。当然,我可以使用 count()
(或任何其他操作)终止流,但这会产生误导,就好像我需要流终止的一些结果一样。在这种情况下终止流的正确方法是什么?
以下是参考代码:
Stream<Collection<NetworkPart>> graphHolders = cutSegment.stream()
.map(this::obtainCollectionFor);
for (NetworkPart part : edgesToNetworkParts.get(originalSegment)) {
part.integrate(cutSegment);
graphHolders = graphHolders.peek(gh -> gh.add(part));
}
graphHolders.count(); // Just to terminate
这就是我重写问题代码的方式:
Collection<NetworkPart> partsOwningEdge = edgesToNetworkParts.get(originalSegment);
partsOwningEdge.forEach(part -> part.integrate(cutSegment));
cutSegment.stream()
.map(this::obtainCollectionFor)
.forEach(gh -> gh.addAll(partsOwningEdge));
如果只是“误导”让您烦恼,请尝试以下操作:
private static void terminateStream(Stream<?> stream) {
stream.forEach(e -> {});
}
我认为这会消除任何歧义:该方法有明确的目的,并且调用也很明确。当如下使用时,
public static void main(String[] args) {
Stream<String> stream = Arrays.asList("a", "b", "c").stream();
stream = stream.peek(str -> System.out.println(str));
terminateStream(stream);
}
main方法会打印
a
b
c
这确实要求
stream
未关闭并且尚未被操作,否则会抛出 IllegalStateException
。
您可以使用 allMatch() 作为终端操作,因为不需要对所有元素进行评估。
调用“中间”流操作时要小心,尤其是与 peek 结合使用时。来自 JavaDoc:
“如果流实现能够优化部分或全部元素的生成(例如使用 findFirst 等短路操作,或者在 count 中描述的示例中),则不会为这些元素调用该操作元素。”
您的“终止”count()实际上根本阻止了 peek 被调用。
尝试运行此版本:
List<AtomicInteger> ints = List.of(new AtomicInteger(0), new AtomicInteger(0));
Stream<AtomicInteger> streamedInts = ints.stream();
for (int i=0; i<5; i++) {
streamedInts = streamedInts.peek(AtomicInteger::incrementAndGet);
}
streamedInts.count();
ints.forEach(foo -> System.out.println(foo.get()));
然后将“.count()”调用替换为真正终止的内容,例如@DennisW
建议的“.forEach(e -> {})”但是更好的方法是使用终止 forEach 来实际修改元素,正如 @gvlasov 已经建议的那样。
注意:我会评论另一个答案,但遗憾的是我还不允许:|