Java 小溪神秘地消耗了两次

Java 小溪神秘地消耗了两次,java,java-stream,Java,Java Stream,以下代码以java.lang.IllegalStateException结束:流已被操作或关闭 public static void main(String[] args) { Stream.concat(Stream.of("FOOBAR"), reverse(StreamSupport.stream(new File("FOO/BAR").toPath().spliterator(), true)

以下代码以
java.lang.IllegalStateException结束:流已被操作或关闭

public static void main(String[] args) {
    Stream.concat(Stream.of("FOOBAR"),
            reverse(StreamSupport.stream(new File("FOO/BAR").toPath().spliterator(), true)
                            .map(Path::toString)));
}

static <T> Stream<T> reverse(Stream<T> stream) {
    return stream.reduce(Stream.empty(),
            (Stream<T> a, T b) -> Stream.concat(Stream.of(b), a),
            (a, b) -> Stream.concat(b, a));
}
publicstaticvoidmain(字符串[]args){
康卡特河(福巴河),
反向(StreamSupport.stream(新文件(“FOO/BAR”).toPath().spliterator(),true)
.map(路径::toString));
}
静态流反转(流){
返回stream.reduce(stream.empty(),
(a流,T流)->浓缩液(b流,a流),
(a,b)->Stream.concat(b,a));
}
显而易见的解决方案是使用
StreamSupport.stream(…,false)
生成一个非并行流,但我不明白为什么不能并行运行。

stream.empty()
不是一个常量。此方法在每次调用时返回一个新的流实例,该实例将像任何其他流一样被使用,例如,当您将其传递到
stream.concat
中时

因此,
Stream.empty()。这是一个实现细节,碰巧只用于一次顺序缩减,而可能用于多次并行缩减

你可以用

静态流反向(流){
返回stream.map(stream::of)
.reduce((a,b)->Stream.concat(b,a))
.orElseGet(流::空);
}
相反

然而,我只提供了一个学术练习的解决方案。一旦流变大,就会导致过多的
concat
调用,注意:

从重复连接构造流时请小心。访问深度连接流的元素可能导致深度调用链,甚至
stackoverflowerr

通常,当以这种方式使用流API时,生成的底层数据结构将比平面列表昂贵得多

你可以用像

streams=Stream.concat(Stream.of(“FOOBAR”),
反向(新文件(“FOO/BAR”).toPath()).map(路径::toString));
静态流反向(路径p){
ArrayDeque d=新的ArrayDeque();
p、 forEach(d::addFirst);
返回d.stream();
}

静态流反向(路径p){
Stream.Builder b=Stream.Builder();
对于(;p!=null;p=p.getParent())b.add(p.getFileName());
返回b.build();
}
使用Java 9+时,您可以使用真正没有额外存储的流(这并不一定意味着它会更高效):

静态流反向(路径p){
返回Stream.iterate(p,Objects::nonNull,Path::getParent).map(Path::getFileName);
}
Stream.empty()
不是常数。此方法在每次调用时返回一个新的流实例,该实例将像任何其他流一样被使用,例如,当您将其传递到
stream.concat
中时

因此,
Stream.empty()。这是一个实现细节,碰巧只用于一次顺序缩减,而可能用于多次并行缩减

你可以用

静态流反向(流){
返回stream.map(stream::of)
.reduce((a,b)->Stream.concat(b,a))
.orElseGet(流::空);
}
相反

然而,我只提供了一个学术练习的解决方案。一旦流变大,就会导致过多的
concat
调用,注意:

从重复连接构造流时请小心。访问深度连接流的元素可能导致深度调用链,甚至
stackoverflowerr

通常,当以这种方式使用流API时,生成的底层数据结构将比平面列表昂贵得多

你可以用像

streams=Stream.concat(Stream.of(“FOOBAR”),
反向(新文件(“FOO/BAR”).toPath()).map(路径::toString));
静态流反向(路径p){
ArrayDeque d=新的ArrayDeque();
p、 forEach(d::addFirst);
返回d.stream();
}

静态流反向(路径p){
Stream.Builder b=Stream.Builder();
对于(;p!=null;p=p.getParent())b.add(p.getFileName());
返回b.build();
}
使用Java 9+时,您可以使用真正没有额外存储的流(这并不一定意味着它会更高效):

静态流反向(路径p){
返回Stream.iterate(p,Objects::nonNull,Path::getParent).map(Path::getFileName);
}

reduce(…)
from
reverse(Stream)
是一个终端操作。当然,reduce将消耗整个拆分器,但它从中生成的流应该是可用的。为什么在生成非并行流时不使用它?
reduce(…)
from
reverse(stream)
是一个终端操作。当然,reduce会消耗整个拆分器,但它从中生成的流应该是可用的。为什么在生成非并行流时不消耗它?