重复消费Java Stream的三种方法。你选择哪种?

Java中的Stream一旦被消费就会关闭,不能再次使用了。如果的确有需要该怎么办呢?
这里介绍三种重复消费Stream的方法。

1. 从集合再次创建

这里你都不用往下继续看就知道该怎么办,不过我还是放上示例代码:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> stream1 = numbers.stream();
Stream<Integer> stream2 = numbers.stream();

只需要分别消费每个stream就可以。

2. 通过Supplier多次创建

这种方法是大多数网文推荐的办法(他们只提供了这一种方法),比如

Supplier<Stream<Integer>> supplier = () -> Stream.of(1, 2, 3, 4, 5);
Stream<Integer> stream1 = supplier.get();
Stream<Integer> stream2 = supplier.get();

同样地,你能拿到多个相同的stream。

3. 通过Stream Builder多次创建

这种方法用的最少,因为我们很少创建Builder:

IntStream.Builder builder = IntStream.builder();
builder.add(1);
builder.add(2);
builder.add(3);
builder.add(4);
builder.add(5);
IntStream stream1 = builder.build();
IntStream stream2 = builder.build();

建议

那么应该用哪种方法呢?第二种吗?NO!多数情况下应该是第一种。

Both approaches have their own advantages and disadvantages, and the choice between them depends on the specific use case.

Approach 1 (using a collection to create a new stream) is generally simpler and more efficient, especially if the original stream was created from a collection. Since the new stream is created from the same collection, there is no additional memory overhead or processing time required to create it.

Approach 2 (using a supplier to create a new stream) is more flexible, as it allows you to create a new stream from any source, not just a collection. However, it may be less efficient than approach 1, as creating a new stream from a non-collection source may require additional memory or processing time.

In general, if the original stream was created from a collection, approach 1 is recommended. If the original stream was created from a non-collection source, or if you need more flexibility in creating new streams, approach 2 may be more appropriate.

重要更新

以上方案来自GPT3.5,但是经过验证,第三种方案是错误的,Builder并不能重复build()。
image

GPT4:

Note that the Stream.Builder itself cannot be reused once the build method has been called, just like any other stream.

Stream为何不设计成能重复消费

GPT4:
Java中的Stream不能被重复使用,主要是因为它们被设计为一次性的、即时执行的操作序列。以下是一些关于Stream不可重用性的详细解释:

设计哲学:Stream被设计为"流"的概念,即数据从源流向目的地。流被消费后就完成了它的使命。这与传统的集合不同,集合可以被多次访问和修改。
内部迭代:Stream API使用内部迭代,意味着迭代是由Stream自身控制的,而不是由外部代码控制的。一旦迭代完成,Stream的内部状态就表示该流已经被消费。
性能优化:不允许重用Stream有助于性能优化。因为Stream只能被消费一次,所以可以在内部进行一些优化,例如延迟执行和中间操作融合。
避免错误:限制Stream只能被消费一次有助于减少编程错误。如果允许重用Stream,可能会引入复杂的状态管理和同步问题。
惰性执行与短路操作:许多Stream操作是惰性的,并且可以进行短路操作。一旦终端操作被触发,中间操作就会被执行,并且可能会被短路。短路操作允许Stream尽早终止处理。如果Stream被重用,这些惰性和短路特性可能会变得复杂且难以管理。

posted @ 2023-07-21 11:02  大卫小东(Sheldon)  阅读(323)  评论(0编辑  收藏  举报