Java 8 Stream在map内部使用map时关闭了。

4
我正在试图将两个流合并。 我遇到了一个问题,即我的流关闭了,我不明白为什么。 请问有谁能够解释一下为什么会出现以下情况。
下面的代码不起作用。 在flatMap函数上我收到一个异常,说这个流已经关闭了。
private Stream<KeyValuePair<T, U>> joinStreams(Stream<T> first, Stream<U> second) {
        return 
                first
                    .map(x -> second
                                .map(y -> new KeyValuePair<T, U>(x, y))
                        )
                    .flatMap(x -> x);       
    }

当我首先从第二个流中收集列表,然后从该列表中抓取流时,它可以正常工作。请参见下面的示例。

private Stream<KeyValuePair<T, U>> joinStreams(Stream<T> first, Stream<U> second) {
    List<U> secondList = second.collect(Collectors.toList());
    return 
            first
                .map(x -> secondList.stream()
                            .map(y -> new KeyValuePair<T, U>(x, y))
                    )
                .flatMap(x -> x);       
}

我不明白为什么会发生这种情况。请问有人可以解释一下吗?
编辑:
调用此函数的代码示例。
List<Integer> numbers1 = Arrays.asList(1, 2);
List<Integer> numbers2 = Arrays.asList(3, 4);

List<KeyValuePair<Integer, Integer>> combined = joinStreams(numbers1.stream(), numbers2.stream())
                                                    .collect(Collectors.toList());

// Expected result
// 1 3
// 1 4
// 2 3
// 2 4
1个回答

5
问题在于你的代码试图处理第二个Stream两次(对于第一个Stream的每个元素都处理一次)。一个Stream只能被处理一次,就像一个Iterator只能迭代底层类的元素一次。
如果你的第一个Stream只有一个元素,那么代码将可以正常工作,因为第二个Stream只会被处理一次。
在可行的代码中,你为第一个Stream的每个元素产生一个新的Stream(从secondList),所以无论第一个Stream中有多少元素,每个Stream都只会被处理一次。

我明白为什么它不起作用,谢谢!你有关于如何解决这个问题的信息吗?每次都要生成一个新的列表似乎是一种资源浪费。 - Bob
2
@Bob 你可以将两个列表(或集合)作为参数传递给你的方法,而不是两个流。然后你的方法将为第一个列表创建一个流,并根据需要为第二个列表创建多个流,并返回连接后的流。 - Eran
3
@Bob,你也可以接受Supplier<Stream<U>>参数而不是Stream<U>,然后使用supplier.get()方法。这样你就不会局限于从集合创建的流了,例如 joinStreams(stream1, () -> IntStream.range(0,100).boxed()) 这样的代码也能正常工作。对于集合源,你需要写成 joinStreams(stream1, numbers2::stream) 的形式。 - Tagir Valeev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接