1

I am facing this error and have no idea how to debug it. The summary of the question is that I have to get the minimum and maximum of a stream. I cannot use Collections and the stream must be parallelizable. Furthermore, the stream is an argument so it cannot be duplicated. I am not asking for a solution but just what does the error mean.

class MinMax {
    final int min, max;

    static Optional<MinMax> findMinMax(Stream<Integer> instream) {
        if(instream.count() > 0) {
            Optional<MinMax> ans = instream.map(x -> {return new MinMax(x,x);}).reduce((x, y) -> {
                Integer max = x.max;
                Integer min = x.min;
                if (y.min < min){
                    min = y.min;
                } 
                if (y.max > max) {
                    max = y.max;
                }
                return new MinMax(min, max);
            });
            return ans;
        } else {
            return Optional.empty();
        }
    }

    public MinMax(int min, int max) {
        this.min = min;
        this.max = max;
    }
    @Override
    public String toString() {
        return min + ", " + max;
    }
}

Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed at java.base/java.util.stream.AbstractPipeline.(AbstractPipeline.java:203) at java.base/java.util.stream.ReferencePipeline.(ReferencePipeline.java:94) at java.base/java.util.stream.ReferencePipeline$StatelessOp.(ReferencePipeline.java:696) at java.base/java.util.stream.ReferencePipeline$3.(ReferencePipeline.java:189) at java.base/java.util.stream.ReferencePipeline.map(ReferencePipeline.java:188) at MinMax.findMinMax(MinMax.java:11) at Main.main(MinMax.java:46)

Maxime
  • 838
  • 6
  • 18
Jayson
  • 91
  • 6
  • Are you calling `findMinMax` multiple times for the same Stream? – Eran Apr 15 '19 at 08:54
  • 1
    "stream has already been operated upon ". You're using the same stream twice. – Andy Turner Apr 15 '19 at 08:54
  • As a side note, `.map(x -> {return new MinMax(x,x);})` is unnecessarily verbose. You can use `.map(x -> new MinMax(x,x))` instead. Besides that, while a Reduction based solution is simple and correct, a `collect` based solution might be more efficient for large streams, like with the `SummaryStatistics` implementation shown at the end of [this answer](https://stackoverflow.com/a/51378142/2711488). – Holger Apr 16 '19 at 10:13

2 Answers2

3

Using intstream.count() closes the stream (because it needs to process the whole stream in order to count the number of elements). However, your check is totally unecessary because it already returns an optional which will be empty if the stream is.

Vinz243
  • 9,654
  • 10
  • 42
  • 86
  • Processing a Stream and “closing” it are two distinct operations which should not get confused. `count()` processes the Stream, making it unusable, but it does not close it. – Holger Apr 16 '19 at 10:09
  • So what would mean closing in the context of streams? – Vinz243 Apr 16 '19 at 10:29
  • Invoking the `close()` method. See [the class documentation](https://docs.oracle.com/javase/8/docs/api/?java/util/stream/Stream.html): “*Streams have a `BaseStream.close()` method and implement `AutoCloseable`, but nearly all stream instances do not actually need to be closed after use. Generally, only streams whose source is an IO channel (such as those returned by `Files.lines(Path, Charset)`) will require closing. Most streams are backed by collections, arrays, or generating functions, which require no special resource management.*” – Holger Apr 16 '19 at 10:34
1

In Java 8 each Stream is a single-use sequence of data that supports several I/O operations in pipeline.

After the end of the piped operations, the stream instance gets consumed and closed.

If you try to use the same stream one more time at another part of your code, you will get java.lang.IllegalStateException: stream has already been operated upon or closed

In your code you are using it twice: - instream.count() and instream.map()

Laguh
  • 621
  • 2
  • 10
  • 23