Bob
Bob

Reputation: 831

Java 8 Stream Closes when using map inside map

I am trying to join two streams together. I ran into the problem that my stream closes and I don't understand why. Couldn't anyone please explain to me why the following happens.

The code below doesn't work. I get an exception on the flatMap function that the stream is already closed.

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);       
    }

When I first collect a list from the second stream and then grab a stream from that list it does work. See the example below.

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);       
}

I can't figure out why this happens. Could anyone please explain this?

Edit:

Example of the code calling this function.

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

Upvotes: 4

Views: 2666

Answers (1)

Eran
Eran

Reputation: 393851

The problem is that your code attempts to process the second Stream twice (once for each element of the first Stream). A Stream can only be processed once, just like an Iterator can only iterate over the elements of the underlying class once.

If your first Stream had only one element, the code would work, since the second Stream would only be processed once.

In the code that does work, you produce a new Stream (from secondList) for each element of the first Stream, so each Stream is processed once, regardless of how many elements are in the first Stream.

Upvotes: 5

Related Questions