我可以在Java 8中复制流吗?

2022-08-31 13:27:48

有时我想对流执行一组操作,然后使用其他操作以两种不同的方式处理生成的流。

我是否可以在不指定常见初始操作两次的情况下执行此操作?

例如,我希望存在如下方法:dup()

Stream [] desired_streams = IntStream.range(1, 100).filter(n -> n % 2 == 0).dup();
Stream stream14 = desired_streams[0].filter(n -> n % 7 == 0); // multiples of 14
Stream stream10 = desired_streams[1].filter(n -> n % 5 == 0); // multiples of 10

答案 1

无法以这种方式复制流。但是,您可以通过将公共部分移动到方法或 lambda 表达式中来避免代码重复。

Supplier<IntStream> supplier = () ->
    IntStream.range(1, 100).filter(n -> n % 2 == 0);
supplier.get().filter(...);
supplier.get().filter(...);

答案 2

一般来说,这是不可能的。

如果要复制输入流或输入迭代器,则有两个选项:

A.将所有内容保存在收藏中,例如List<>

假设您将一个流复制到两个流中,然后 .如果 中有 高级元素 和 元素,则必须将元素保留在内存中,只是为了跟上步伐。如果您的流是无限的,则所需的存储可能没有上限。s1s2n1s1n2s2|n2 - n1|

看看Python的tee()看看它需要什么:

此迭代工具可能需要大量辅助存储(取决于需要存储多少临时数据)。通常,如果一个迭代器在另一个迭代器启动之前使用了大部分或全部数据,则使用此方法比 使用更快。list()tee()

B.如果可能:复制创建元素的生成器的状态

要使此选项正常工作,您可能需要访问流的内部工作原理。换句话说,生成器 ( 创建元素的部分 - 首先应该支持复制。[OP:请参阅这个很好的答案,作为问题中的示例如何执行此操作的示例]

它不适用于用户的输入,因为您必须复制整个“外部世界”的状态。Java不支持复制,因为它被设计为尽可能通用;例如,处理文件,网络,键盘,传感器,随机性等[OP:另一个例子是按需读取温度传感器的流。如果不存储读数的副本,就无法复制它]Stream

这不仅在Java中是这样;这是一般规则。您可以看到C++中的std::istream仅支持移动语义,而不支持复制语义(“复制构造函数(已删除)”),因此(以及其他原因)。


推荐