Wednesday, 4 May 2016

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

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

In Java 8 a Stream object cannot be reused after it has been reused or worked upon.
After any Stream operation, that particular Stream will be closed automatically.

See the Example below:

import java.util.Arrays;
import java.util.stream.Stream;

public class StreamTestingClass {
 public static void main(String[] args) {

 String[] array = new String[]{"a", "b","c","d"};
        Stream dataStream = Arrays.stream(array);
        
        //Using the dataStream 1st time
        dataStream.forEach(System.out::println);

        //Using the dataStream for the 2nd time.. GIVES EXCEPTION!!
        dataStream.forEach(System.out::println);
 }
}


This will give the following Exception:

a
b
c
d
Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed
 at java.util.stream.AbstractPipeline.sourceStageSpliterator(AbstractPipeline.java:279)
 at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)
 at codermag.net.java8.StreamTestingClass.main(StreamTestingClass.java:15)




This proves that the command executes for the 1st time.
For the 2nd time it fails.


SOLUTION: Use java.util.function.Supplier Class

To reuse a Stream we need to use java.util.function.Supplier.
java.util.function.Supplier allows you to get multiple instance of the same Stream.


import java.util.Arrays;
import java.util.function.Supplier;
import java.util.stream.Stream;

public class StreamTestingClass {
 public static void main(String[] args) {

  String[] array = new String[]{"a", "b","c","d"};
       
  Supplier<Stream<String>> streamSupplier = () -> Arrays.stream(array);
        
  //get a copy of the stream
  streamSupplier.get().forEach(System.out::println);

        //get another copy of the stream
  streamSupplier.get().forEach(System.out::println);
 }
}


The get() operation of java.util.function.Supplier.get() is used to get a new instance of the Stream.
This will help you to work on the Stream multiple times. Just call the get() as many times as required.