Closing Streams in Java

Close Java 8 Stream

It is generally not necessary to close streams at all. You only need to close streams that use IO resources.

From the Stream documentation:

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. (If a stream does require closing, it can be declared as a resource in a try-with-resources statement.)

If you need to close a stream, then best practice would be to use the try-with-resources statement:

try ( Stream<String> stream = Files.lines(path, charset) ) {
// do something
}

What is the correct order to close input streams?

The normal thing to do is to only close the outermost stream. DataInputStream and BufferedInputStream are both types of FilterInputStream, whose close method specifies that it calls the close method of the underlying stream. So you do not need to explicitly close the others or even maintain a reference to them in a variable. For example it is fine to initialize dis as:

dis = new DataInputStream(
new BufferedInputStream(
new FileInputStream(file)));

In practice, assuming the classes are implemented properly according to the spec, it does not matter whether you close any 1, any 2, or all 3 of the streams, in any order, or any number of times, because:

  1. As said, closing an outer stream closes the inner stream.
  2. Closing an already closed stream harmlessly does nothing. (InputStream and OutputStream implement the Closeable interface, whose close method states "If the stream is already closed then invoking this method has no effect.")
  3. Only the FileInputStream actually needs to be closed, since it is the only one which holds open a real filesystem resource and therefore is the only stream which has visible side effects if held open (e.g., you cannot delete the file). The BufferedInputStream and DataInputStream are ordinary objects, which can be garbage collected in the ordinary way, whether closed or not. The FileInputStream will also be closed when garbage collected if you forgot to do it, but it's prudent to do it as soon as possible, since there are no guarantees about when garbage collection occurs.

So the example you posted is over-engineered, but not dangerous.

In modern Java (7+) the far more elegant way to ensure the closure of everything in your example, rather than using a finally block, is to use the try-with-resources statement, which lets you declare the streams, open them, and guarantee their closure, in one go:

try (DataInputStream dis = new DataInputStream(
new BufferedInputStream(
new FileInputStream(file)))) {
while (dis.available() != 0) {
System.out.println(dis.readLine());
}
} catch (IOException e) {
e.printStackTrace();
}

Closing a nested stream closes its parent streams too?

Yes, it does. Its Javadoc says:

Closes the ZIP output stream as well as the stream being filtered.

Also, the Javadoc for BufferedOutputStream says:

Closes this output stream and releases any system resources associated with the stream.

The close method of FilterOutputStream calls its flush method, and then calls the close method of its underlying output stream.

So when you close your ZipOutputStream, it will close your BufferedOutputStream, which will in turn close your FileOutputStream.

Closing a Java 8 stream opened by flatMap in case of exception?

The source shows that the Stream returned to flatMap is immediately wrapped in a try with resources, so it will be closed even if a downstream operation throws an exception.

It might be a good idea to update the flatMap javadoc to explicitly state that this will happen.

Why doesn't Java close() stream after a terminal operation is issued?

Because streams that require explicit resource release is actually a pretty unusual case. So we chose not to burden all stream execution with something that is only valuable for .01% of usages.

We made Stream Autocloseable so that you can release resources from the source if you want to, but this is where we stopped, and for a good reason.

Not only would doing this automagically burden the majority of users with extra work that they don't need, but this would also violate a general principle: he who allocates the resource is responsible for closing the resource. When you call

BufferedReader reader = ...
reader.lines().op().op()...

you are the one opening the resource, not the stream library, and you should close it. In fact, since closing a stream resulting from calling an accessor method on some resource-holding object will sometimes close the underlying object, you probably don't want the stream closing the BufferedReader for you -- you might want it to stay open after the call.

If you want to close the resource, this is easy too:

try (BufferedReader reader = ...) {
reader.lines().op()...
}

You're probably using streams in a particular way, so it probably seems "obvious" what streams should do -- but there are more use cases out there than yours. So rather than catering to specific use cases, we approached it from the general principle: if you opened the stream, and you want it closed, close it yourself, but if you didn't open it, it's not for you to close.

How to close nested I/O streams in Java

The docs of the close method of BufferedOutputStream (inherited from FilterOutputStream) says

The close method of FilterOutputStream calls its flush method, and then calls the close method of its underlying output stream.

So IntelliJ is clearly wrong. If in doubt trust the documentation, not the IDE's warnings - they are warnings and not errors for a reason.

That said, you should use a try-with-resources statement.

And you also do not need an intermediate variable, you can construct the FOS and immediately pass it as argument to the BOS constructor.



Related Topics



Leave a reply



Submit