首页 > 解决方案 > 嵌套流异常

问题描述

我想从所有字符串中返回字符串的排列。当我使用下面的代码时,我得到java.lang.IllegalStateException: stream has already been operated upon or closed. 你能告诉我这种方法有什么问题吗?

public Stream<String> getMyPatterns(
        Stream<String> s1,
        Stream<String> s2,
        Stream<String> s3) {
    List<String> out = new ArrayList<String>();
    s1.collect(Collectors.toList()).forEach(item1 -> {
        s2.collect(Collectors.toList()).forEach(item2 -> {
            s3.collect(Collectors.toList()).forEach(item3 -> {
                out.add(item1 + "." + item2 + "." + item3);
            });
        });
    });
    return out.stream();
}

样品测试

Stream<String> patterns = getMyPatterns(
            Stream.of("a1", "a2"),
            Stream.of("b1", "b2"),
            Stream.of("c1", "c2"));

标签: javajava-8java-stream

解决方案


正如其他人所暗示的那样,您正在多次s2使用Streams 。s3forEach

另一方面,在返回 Stream 之前收集结果列表是没有意义的。forEach无论如何,当有其他更合适的操作时,您不应该使用。

您只需要收集您想要与上一个组合的Stream。这最好通过首先解决两个流的组合来完成:

public Stream<String> getMyPatterns(Stream<String> s1, Stream<String> s2) {
    List<String> s2List = s2.collect(Collectors.toList());
    return s1.flatMap(item1 -> s2List.stream().map(item2 -> item1+'.'+item2));
}

然后,您可以轻松地递归使用此方法来解决组合三个 Streams 的任务:

public Stream<String> getMyPatterns(Stream<String> s1,Stream<String> s2,Stream<String> s3) {
    return getMyPatterns(getMyPatterns(s1, s2), s3);
}

这只收集尽可能少的必要,即它不会收集第一个 Stream,因此它的消费只会在返回的 Stream 被消费时开始。

Stream<String> patterns = getMyPatterns(
    Stream.of("a1", "a2").peek(s -> System.out.println("consuming "+s)),
    Stream.of("b1", "b2"),
    Stream.of("c1", "c2"));

System.out.println("start consuming result Stream");
System.out.println(patterns.collect(Collectors.joining(", ")));
start consuming result Stream
consuming a1
consuming a2
a1.b1.c1, a1.b1.c2, a1.b2.c1, a1.b2.c2, a2.b1.c1, a2.b1.c2, a2.b2.c1, a2.b2.c2

推荐阅读