Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correct way to close nested streams and writers in Java [duplicate]

Tags:

java

java-io

Note: This question and most of its answers date to before the release of Java 7. Java 7 provides Automatic Resource Management functionality for doing this easilly. If you are using Java 7 or later you should advance to the answer of Ross Johnson.


What is considered the best, most comprehensive way to close nested streams in Java? For example, consider the setup:

FileOutputStream fos = new FileOutputStream(...) BufferedOS bos = new BufferedOS(fos); ObjectOutputStream oos = new ObjectOutputStream(bos); 

I understand the close operation needs to be insured (probably by using a finally clause). What I wonder about is, is it necessary to explicitly make sure the nested streams are closed, or is it enough to just make sure to close the outer stream (oos)?

One thing I notice, at least dealing with this specific example, is that the inner streams only seem to throw FileNotFoundExceptions. Which would seem to imply that there's not technically a need to worry about closing them if they fail.

Here's what a colleague wrote:


Technically, if it were implemented right, closing the outermost stream (oos) should be enough. But the implementation seems flawed.

Example: BufferedOutputStream inherits close() from FilterOutputStream, which defines it as:

 155       public void close() throws IOException {  156           try {  157             flush();  158           } catch (IOException ignored) {  159           }  160           out.close();  161       } 

However, if flush() throws a runtime exception for some reason, then out.close() will never be called. So it seems "safest" (but ugly) to mostly worry about closing FOS, which is keeping the file open.


What is considered to be the hands-down best, when-you-absolutely-need-to-be-sure, approach to closing nested streams?

And are there any official Java/Sun docs that deal with this in fine detail?

like image 389
dirtyvagabond Avatar asked May 19 '09 17:05

dirtyvagabond


People also ask

How do you close streams in Java?

From the docs: 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.

Do we need to close Outputstreamwriter?

No, the topmost level Stream or reader will ensure that all underlying streams / readers are closed.

Do we need to close OutputStream in Java?

Close an OutputStreamOnce you are done writing data to a Java OutputStream you should close it.

What happens if you don't close a stream in Java?

if you not closing the connection ,then for every user the connection will create .. remember there is a limited number of connection only . so for the next user he wont get the connection to DataBase . what will happen if we don't close the streams?


2 Answers

When closing chained streams, you only need to close the outermost stream. Any errors will be propagated up the chain and be caught.

Refer to Java I/O Streams for details.

To address the issue

However, if flush() throws a runtime exception for some reason, then out.close() will never be called.

This isn't right. After you catch and ignore that exception, execution will pick back up after the catch block and the out.close() statement will be executed.

Your colleague makes a good point about the RuntimeException. If you absolutely need the stream to be closed, you can always try to close each one individually, from the outside in, stopping at the first exception.

like image 157
Bill the Lizard Avatar answered Sep 28 '22 03:09

Bill the Lizard


In the Java 7 era, try-with-resources is certainly the way to go. As mentioned in several previous answers, the close request propagates from the outermost stream to the innermost stream. So a single close is all that is required.

try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f))) {   // do something with ois } 

There is however a problem with this pattern. The try-with-resources is not aware of the inner FileInputStream, so if the ObjectInputStream constructor throws an exception, the FileInputStream is never closed (until the garbage collector gets to it). The solution is...

try (FileInputStream fis = new FileInputStream(f); ObjectInputStream ois = new ObjectInputStream(fis)) {   // do something with ois } 

This is not as elegant, but is more robust. Whether this is actually a problem will depend on what exceptions can be thrown during construction of the outer object(s). ObjectInputStream can throw IOException which may well get handled by an application without terminating. Many stream classes only throw unchecked exceptions, which may well result in termination of the application.

like image 41
Ross Johnson Avatar answered Sep 28 '22 04:09

Ross Johnson