我想复制一个Java 8流,这样我可以处理它两次。我可以collect
作为一个列表,并从中获得新的流;
// doSomething() returns a stream
List<A> thing = doSomething().collect(toList());
thing.stream()... // do stuff
thing.stream()... // do other stuff
但我认为应该有一种更有效/更优雅的方式。
有没有一种方法可以复制流而不将其转换为集合?
我实际上是在处理一个Either
流,所以我想先处理左投影,然后再转到右投影,然后再用另一种方法处理。有点像这样(到目前为止,我不得不使用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 -> ... );
发布于 2014-05-26 08:00:32
我认为你关于效率的假设是一种倒退。如果您只使用数据一次,那么您将获得巨大的效率回报,因为您不必存储它,并且streams为您提供了强大的“循环融合”优化,使您可以通过管道高效地流动整个数据。
如果您想重用相同的数据,那么根据定义,您必须生成两次(确定性的)或存储它。如果它恰好已经在一个集合中,那就太好了;那么迭代两次是很便宜的。
我们在设计中用"forked streams“做了实验。我们发现,支持这一点是有实际成本的;它以牺牲不常见的情况为代价,增加了常见情况(使用一次)的负担。最大的问题是如何处理“当两个管道不以相同的速率消耗数据时会发生什么”。现在,你又回到了缓冲状态。这是一个明显没有分量的特性。
如果您希望对同一数据进行重复操作,请存储该数据,或者将您的操作构建为消费者并执行以下操作:
stream()...stuff....forEach(e -> { consumerA(e); consumerB(e); });
您还可以研究一下RxJava库,因为它的处理模型更适合这种“流分叉”。
发布于 2015-06-19 01:34:44
您可以使用带有Supplier
的局部变量来设置流管道的公共部分。
来自http://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/
重用Streams
Java 8流不能重用。只要调用任何终端操作,流就会关闭:
Stream stream = Stream.of("d2","a2","b1","b3","c") .filter(s -> s.startsWith("a"));stream.anyMatch(s -> true);// ok stream.noneMatch(s -> true);//在同一个流上的anyMatch
之后调用noneMatch
的异常导致以下异常: java.lang.IllegalStateException:流已经在java.util.stream.ReferencePipeline.noneMatch(ReferencePipeline.java:459)处的com.winterbe.java8.Streams5.test7(Streams5.java:38)处的com.winterbe.java8.Streams5.main(Streams5.java:28)处的java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:229)处操作或关闭
为了克服这一限制,我们必须为我们想要执行的每个终端操作创建一个新的流链,例如,我们可以创建一个流供应商来构造一个已经设置了所有中间操作的新流:
Supplier 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()
的调用都会构造一个新的流,我们将在该流上保存以调用所需的终端操作。
发布于 2018-03-05 14:50:19
使用Supplier
为每个终止操作生成流。
Supplier<Stream<Integer>> streamSupplier = () -> list.stream();
无论何时需要该集合的流,都可以使用streamSupplier.get()
来获取新的流。
示例:
streamSupplier.get().anyMatch(predicate);
streamSupplier.get().allMatch(predicate2);
https://stackoverflow.com/questions/23860533
复制相似问题