我想复制一个Java 8流,以便可以处理两次。我可以collect列出并从中获得新的信息流;
// doSomething() returns a stream List<A> thing = doSomething().collect(toList()); thing.stream()... // do stuff thing.stream()... // do other stuff
但我认为应该有一种更有效/更优雅的方法。
有没有一种方法可以复制流而不将其转换为集合?
我实际上正在使用Eithers 流,因此想先处理左侧投影,然后再移至右侧投影并以另一种方式处理。有点像这样(到目前为止,我被迫使用这种toList技巧)。
Eithers
toList
List<Either<Pair<A, Throwable>, A>> results = doSomething().collect(toList()); Stream<Pair<A, Throwable>> failures = results.stream().flatMap(either -> either.left()); failures.forEach(failure -> ... ); Stream<A> successes = results.stream().flatMap(either -> either.right()); successes.forEach(success -> ... );
你可以将局部变量与一起使用,Supplier以设置流管道的公共部分。
Supplier
从http://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/:
重用流
Java 8流无法重用。调用任何终端操作后,流就立即关闭:
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 Calling `noneMatch` after `anyMatch` on the same stream results in the following exception: java.lang.IllegalStateException: stream has already been operated upon or closed at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:229) at java.util.stream.ReferencePipeline.noneMatch(ReferencePipeline.java:459) at com.winterbe.java8.Streams5.test7(Streams5.java:38) at com.winterbe.java8.Streams5.main(Streams5.java:28)
为了克服此限制,我们必须为要执行的每个终端操作创建一个新的流链,例如,我们可以创建一个流提供程序以构造一个已经设置了所有中间操作的新流:
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()构造一个新的流,我们可以保存该流以调用所需的终端操作。