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 implementAutoCloseable
, 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 byFiles.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:
- As said, closing an outer stream closes the inner stream.
- Closing an already closed stream harmlessly does nothing. (
InputStream
andOutputStream
implement theCloseable
interface, whoseclose
method states "If the stream is already closed then invoking this method has no effect.") - 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). TheBufferedInputStream
andDataInputStream
are ordinary objects, which can be garbage collected in the ordinary way, whether closed or not. TheFileInputStream
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 ofFilterOutputStream
calls itsflush
method, and then calls theclose
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
Creating an Animated 4X4 Grid in Java
Copying Text to the Clipboard Using Java
How to Implement a Fsm - Finite State MAChine in Java
Find Files in a Folder Using Java
How to Add Test Coverage to a Private Constructor
Is Doing a Lot in Constructors Bad
What Is an "Internal Address" in Java
Closing Bufferedreader and System.In
How to Send Java.Util.Logging to Log4J
"Faceted Project Problem (Java Version Mismatch)" Error Message
How to Get Java Logging Output to Appear on a Single Line
How to Implement Infinity in Java
Retrieve an Image Stored as Blob on a MySQL Db
Annotations from Javax.Validation.Constraints Not Working
Import Sun.Misc.Base64Encoder Results in Error Compiled in Eclipse