Java – Stream has already been operated upon or closed
In Java 8, Stream cannot be reused, once it is consumed or used, the stream will be closed.
1. Example – Stream is closed!
Review the following example, it will throw an IllegalStateException
, saying “stream is closed”.
TestJava8.java
package com.mkyong.java8;
import java.util.Arrays;
import java.util.stream.Stream;
public class TestJava8 {
public static void main(String[] args) {
String[] array = {"a", "b", "c", "d", "e"};
Stream<String> stream = Arrays.stream(array);
// loop a stream
stream.forEach(x -> System.out.println(x));
// reuse it to filter again! throws IllegalStateException
long count = stream.filter(x -> "b".equals(x)).count();
System.out.println(count);
}
}
Output
java.lang.IllegalStateException: stream has already been operated upon or closed at java.util.stream.AbstractPipeline.(AbstractPipeline.java:203) at java.util.stream.ReferencePipeline. (ReferencePipeline.java:94) at java.util.stream.ReferencePipeline$StatelessOp. (ReferencePipeline.java:618) at java.util.stream.ReferencePipeline$2. (ReferencePipeline.java:163) at java.util.stream.ReferencePipeline.filter(ReferencePipeline.java:162) at com.hostingcompass.whois.range.run.TestJava8.main(TestJava8.java:25) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
2. Example – Reuse a stream
For whatever reason, you really want to reuse a Stream, try the following Supplier
solution :
TestJava8.java
package com.mkyong.java8;
import java.util.function.Supplier;
import java.util.stream.Stream;
public class TestJava8 {
public static void main(String[] args) {
String[] array = {"a", "b", "c", "d", "e"};
Supplier<Stream<String>> streamSupplier = () -> Stream.of(array);
//get new stream
streamSupplier.get().forEach(x -> System.out.println(x));
//get another new stream
long count = streamSupplier.get().filter(x -> "b".equals(x)).count();
System.out.println(count);
}
}
Output
a b c d e 1
Each get()
will return a new stream.
Why?
May I know why you need to reuse a stream, for testing?
May I know why you need to reuse a stream, for testing?
How to use with try and resources Supplier
//read file into stream, try-with-resources
try (Stream stream = Files.lines(Paths.get(fileName))) {
stream.forEach(System.out::println);
if(list.size() ===0)
try (Stream stream = Files.lines(Paths.get(fileName))) {
stream.forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}
Supplier is not AutoCloseable, so u can’t use it in try()
stream could be reused while generating reports
Thank you mkyong, that’s really helpful
how to work with int[] instead of String[]
thank you for great article
The input param for “Stream.of(array)” is only accept an array?
you could check the Javadoc for yourself, wouldn’t hurt.. I promise
Very good article!