Nishant Kumar
Nishant Kumar

Reputation: 73

Using Stream StreamSupplier

I'm using following code to reuse Stream but getting

java.lang.IllegalStateException: stream has already been operated upon or closed

Code

public static void main(String[] args) {

    try {
        String[] array = { "a", "b", "c", "d", "e" };
        Stream<String> ss = Stream.of(array);
        Supplier<Stream<String>> streamSupplier = () -> ss;

        long count = streamSupplier.get().count();
        // get new stream
        streamSupplier.get().forEach(x -> System.out.println(x));

        // get another new stream

        System.out.println(count);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Upvotes: 7

Views: 4570

Answers (4)

Nikolas
Nikolas

Reputation: 44408

Stream::count is the terminal operation which closes the Stream, so no more pipelines can proceed.

You create the Stream<String> before you put it to the Supplier. If you want the Supplier to provide a new Stream witch each call, create the Stream<String> directly in the Supplier.

Supplier<Stream<String>> streamSupplier = () -> Stream.of(array);

Then streamSupplier.get() will always work with the new Stream<Stream>.


Yet, you might achieve the same result with Stream::peek which works the same like Stream::forEach with an exception that it doesn't close the Stream but returns the same unmodified one (@Lino was faster).

long count = streamSupplier.get().peek(System.out::println).count();

Upvotes: 4

Lino
Lino

Reputation: 19926

Don't assign Stream.of(array) to an intermediate variable, just return it directly in the Supplier:

Supplier<Stream<String>> streamSupplier = () -> Stream.of(array);

That is because previously you would just always supply the same reference when calling supplier.get() but in fact you wanted to return a new Stream.

Also as @Eugene suggested, using Arrays.stream() over Stream.of() is preferred. As the latter is a varargs method, but just delegates to the former.


Also your current approach can be simplified using the Stream.peek() method:

long count = Arrays.stream(array)
    .peek(System.out::println)
    .count();

Upvotes: 8

nikodaemus
nikodaemus

Reputation: 2128

The exception you're getting is appropriate and tells you what you need to research. From the Java 8 Stream class:

A stream should be operated on (invoking an intermediate or terminal stream operation) only once. This rules out, for example, "forked" streams, where the same source feeds two or more pipelines, or multiple traversals of the same stream. A stream implementation may throw IllegalStateException if it detects that the stream is being reused. However, since some stream operations may return their receiver rather than a new stream object, it may not be possible to detect reuse in all cases.

Upvotes: 2

CTroller
CTroller

Reputation: 166

You're still using the same Stream over and over again. Move the Stream.of(array) within the supplier, not outside.

Upvotes: 0

Related Questions