2017-03-02 32 views
2

我知道,只要我们调用stream上的任何terminal method,它就会关闭。如何在Java流上调用多个终端操作

如果我们试图在封闭流上调用任何其他终端函数,将会产生一个java.lang.IllegalStateException: stream has already been operated upon or closed

但是,如果我们想重复使用同一个流不止一次

如何做到这一点?

+4

这是一个严酷的事实:您无法重新使用流。你可以把你从你的*输入*中获得流,并再次流。另外,根据您所面对的确切问题*,您可能只通过流式播放一次来获得所需的结果。 – Eugene

+1

请参阅http://stackoverflow.com/questions/28459498/why-are-java-streams-once-off为理由 – user140547

+0

为什么你想重用他们呢?你希望通过这样做来达到什么目的? – Rogue

回答

3

是它的一个很大的NO在Java中8流重用流

例如,对于任何终端操作时的操作被关闭时流关闭。但是,当我们使用Stream链中,我们能够避免此异常:

普通终端操作:

Stream<String> stream = 
    Stream.of("d2", "a2", "b1", "b3", "c") 
     .filter(s -> s.startsWith("a")); 

stream.anyMatch(s -> true); // ok 
stream.noneMatch(s -> true); // exception 

但不是这个,如果我们使用:

Supplier<Stream<String>> streamSupplier = 
    () -> Stream.of("d2", "a2", "b1", "b3", "c") 
      .filter(s -> s.startsWith("a")); 

streamSupplier.get().anyMatch(s -> true); // ok 
streamSupplier.get().noneMatch(s -> true); // ok 

这里.get() “构造”一个​​新的流,并且在它碰到这个点时不被重用。

干杯!

+1

那么,这是一个解决方法,但不是要求的:“如果我们想重复使用相同的流*不止一次” –

+0

这不是可重用性。 请阅读关于** get()**的最后一行。 –

+0

在Java 8中,流不能基本重用,并非真正在终端操作中。答案是不。 –

0

不,您不能重复使用Stream,但是,如果超载堆空间不是问题,您可以使用Stream.Builder在终端操作重新使用之前保存流内容。例如:

Stream<OriginalType> myStream = ... 
Stream.Builder<SomeOtherType> copy = Stream.builder(); 
List<SomeOtherType> aList = myStream 
    .filter(...) 
    .map(...)  // eventually maps to SomeOtherType 
    .peek(copy) // pour values into a new Stream 
    .collect(Collectors.toList()); 
Set<SomeOtherType> aSet = copy.build() 
    .collect(Collectors.toSet()); 

有人可能会保持链接流在一起,在每个连续Stream添加新Stream.Builder实例。

不是您正在寻找的答案,但它确实避免了第二次执行管线操作的开销。它有其自身的弱点,被限制在堆空间中,但它没有Holger在他对Supplier解决方案的评论中建议的弱点 - 如果它是Random流,它将在第二次迭代中具有相同的值。