Why is not possible to reopen a closed (standard) stream?

Solution 1:

why is not possible to reopen a closed stream in Java?

That's simply the nature of the underlying operating system constructs that Java streams represent. A stream is essentially a data conduit. Once you close it, it no longer exists. You may be able to create a new one between the same endpoints, but that yields a fundamentally different stream. We could go into implementation considerations such as buffering and stream positioning, but those are really side issues.

You also asked specifically about the standard streams. These are some of the cases that you cannot recreate. The operating system provides each process with its set of standard streams. Once they are closed, there is no way to obtain equivalents. You can put different streams in their place, but you cannot connect them to the original endpoints.

Solution 2:

When you close the standard input stream:

  • If your input was being provided by a pipe, the other end of the pipe is notified. It will close its end and stop sending data. There is no way to tell it you made a mistake and it should start sending again;

  • If your input was being provided by a file, the OS drops its reference to the file and completely forgets that you were using it. There is just no way provided for you to reopen standard input and continue reading;

  • If your input was being provided by the console, it works with a pipe. The console is notified, will close its end of the pipe and stop sending you data.

So there's no way to reopen standard input.

BUT... there is also no reason to close standard input, so just don't do that!

A good pattern to follow is:

  • The code or class that opens a file is responsible for closing it.

  • If you pass an InputStream to another method that reads from it, that method should not close it. Leave that to the code that opened it. It's like the streams owner.

  • Similarly, if you pass an OutputStream to another method that writes to it, that method should not close it. Leave that to the code that owns it. BUT if you wrap the stream in other classes that may buffer some data do call .flush() on them to make sure everything comes out!

  • If you're writing your own wrapper classes around InputStream and OutputStream, don't close the delegate stream in your finalizer. If a stream needs to be cleaned up during GC, it should handle that itself.

In your example code, just don't close that Scanner. You didn't open standard input, so you shouldn't need to close it.

Solution 3:

Because Streams are unbounded. You peek values from streams as you need. Then when done simply close it. Streams does not hold it's all data in memory. Streams are designed to process relatively big amount of data which can't be held in memory. So you can't reopen an stream simply because you already have made a loop over it and exhausted all the data. As stream does not hold those data in memory. They are simply lost and that's why you can't reopen it. The better is you create a new stream than reopen an existing one.