Disposing streams in Java
Asked Answered
H

4

13

In C#, I almost always use the using pattern when working with stream objects. For example:

using (Stream stream = new MemoryStream())
{
    // do stuff
}

By using the using block, we ensure that dispose is called on the stream immediately after that code bock executes.

I know Java doesn't have the equivalent of a using keyword, but my question is that when working with an object like a FileOutputStream in Java, do we need to do any housekeeping to make sure it gets disposed? I was looking at this code example, and I noticed they don't do any.

I just wondered what the best practice was for Java in handling disposing streams, or if it's good enough to let the garbage collector handle it.

Hevesy answered 15/2, 2010 at 19:41 Comment(0)
C
11

generally, you have to do the following:

InputStream stream = null;
try {
   // IO stuff - create the stream and manipulate it
} catch (IOException ex){
  // handle exception
} finally {
  try {
     stream.close();
  } catch (IOException ex){}
}

But apache commons-io provides IOUtils.closeQuietly(stream); which is put in the finally clause to make it a little less-ugly. I think there will be some improvement on that in Java 7.

Update: Jon Skeet made a very useful comment, that the actual handling of the exception is rarely possible to happen in the class itself (unless it is simply to log it, but that's not actually handling it). So you'd better declare your method throw that exception up, or wrap it in a custom exception (except for simple, atomic operations).

Copley answered 15/2, 2010 at 19:43 Comment(6)
Do you know if IOUtils.closeQuietly(stream) handles a null stream, otherwise it could throw NPE and cause the same problem (original exception gets eaten).Hevesy
yes, IOUtils checks for null before closing, so no risk of NPECopley
According to the official Java Tutorial, you only close a stream when it is not null.Casia
naturally, you can't do anything with null references, except check against them.Copley
I find it's very rare that I can actually handle an IOException within a low-level method like this. It almost always involves throwing an exception of some kind. Note that you're also swallowing an IOException thrown during close; that's often the right thing to do if the code has already thrown an exception, but may well hide an error otherwise. For example, if you write several items to a BufferedOutputStream but leave it to the close() method to flush appropriately, swallowing the exception hides the fact that the write has essentially failed.Odeliaodelinda
don't forget to add if(null != stream) condidion )Alit
D
6

The feature you want was indeed introduced in Java 7, under the name "try-with-resources statement" (also known as automatic resource management (ARM)). Here is the code:

try (InputStream in = new FileInputStream("foo.txt")) {
    ...
}  // This finally calls in.close()
Ducal answered 1/7, 2019 at 14:57 Comment(1)
This is the best syntax, in the case of errors, you get to keep both the exception thrown from the code and the exception from closeKonya
O
4

There's (sadly) no equivalent of the using statement in Java, although there have been some thoughts about including something similar in Java 7. (I think last time I looked they were "out", but I find it hard to keep up with the status of features in Java 7.)

Baically you need a try/finally block:

InputStream stream = new FileInputStream(...);
try { 
    ...
} finally {
    stream.close();
}

There's then the problem of what to do with the IOException in the case of the close() failing, and the problem of an exception there "overwriting" any exception thrown by the main body of the code - although the latter is a problem in .NET too.

Guava makes this slightly easier with the Closeables class, with static close and closeQuietly methods which will deal with stream being null (in the case where you declare the variable before the block but assign the value within the try block).

Odeliaodelinda answered 15/2, 2010 at 19:45 Comment(3)
Creating the stream also throws IOException, so it should be in the try/catch/finally as well.Copley
But using Bozho's way above would cause the original exception to be preserved, right, since he's basically eating the IOException that could be thrown. Also, I think you should probably check stream for null, otherwise NPE could result couldn't it?Hevesy
@Copley and dcp: Usually when I deal with streams it's within a method which is declared to throw IOException, so I rarely catch it at that level. That's where you get into problems. The code given here doesn't need to check for nullity, as I'm calling a constructor: if that method returns without an exception, stream definitely won't be null.Odeliaodelinda
W
2

In case anybody is curious the new syntax in Java 7 could be:

do (BufferedInputStream bis = ...; BufferedOutputStream bos = ...) {
   ... // Perform action with bis and bos
}

(See proposal by Joshua Bloch)

Here is a related thread on Stack Overflow.

Weese answered 15/2, 2010 at 20:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.