Wrapping Constructed Streams and Proper Closing
So I've just recently had one of those moments wherein I find out that something I assumed to be true was not. I had believed for quite some time that the closes in the following snippet were necessary (all of them):
FileOutputStream fos =new FileOutputStream(file);
GZIPOutputStream gzos =new GZIPOutputStream(fos);
ObjectOutputStream oos =new ObjectOutputStream(gzos);
os.writeObject(new Object());
oos.close();
gzos.close();
fos.close();
It wasn't until recently I found out that you can just do this:
OutputStream os =new ObjectOutputStream(new ObjectOutputStream(new FileOutputStream(file)));
os.writeObject(new Object());
os.close();
because the call to ObjectOutputStream.close() is expected to close all of the underlying streams.
Well, that's all delightful, but it doesn't address an error handling concern I have. In the chained constructor call, the FileOutputStream is constructed first, followed by the GZIPOutputStream and finally by the ObjectOutputStream. It is my understanding that I am to make sure that all of the streams I open are closed, whether directly or indirectly. What if ObjectOutputStream throws an exception? In that case, the FileOutputStream has been constructed but not closed and I do not have a reference to it.
My first impression is that I will have to keep a reference to it or (in this case) the GZIPOutputStream to ensure it is properly closed. Is this the only way to handle this problem? I know that finalize() will likely close it for me whenever the garbage collector finds it, but that's not guaranteed to happen at all, much less within a timely period.
So perhaps I will go on creating streams like I did before and not use so many close calls?
This is just me thinking aloud in a mildly tired state. But if anyone has any suggestions, I'd love to hear them.
Thanks. :)
[2202 byte] By [
tvynra] at [2007-10-2 20:15:27]

Don't fret. Think of it this way. I have three output streams nested from #1 to #3. What should I do if #3 closes, but #2 throws an exception? Clearly, I cannot re-close #3. Attempting to close #2 is also a non-starter, as the previous attempt failed. What to do with #1? Well, it all depends. Nearly all streams flush() on a close(), and a good many perform additional closing operations (such as cryptographic streams) prior even to flush(), issuing additional calls to an underlying write().
So, IMO, once the process short-circuits, you should treat it as an unrecoverable exception. It may be recoverable, but you will probably invest significant intellectual and debugging effort to provide this.
- Saish
Saisha at 2007-7-13 22:57:45 >

But doesn't that mean that any system resources I might be using are still tied up? The FileOutputStream's resources would be freed as soon as it got garbage collected, but I can't assure that that is going to happen in any reasonable amount of time... so my JVM is consuming a spare open file handle or whatever else might've been tapped.
So, let's assume I'm paranoid or compulsive or whatever... can anyone think of a simpler or cleaner way of doing this?
OutputStream bos = null;
OutputStream os = null;
try
{
bos = new FileOutputStream(file); // base stream
os = new ObjectOutputStream(new GZIPOutputStream(bos));
// do stream stuff
} catch (IOException ioe)
{
// do exception handling stuff -- maybe a couple try-catch blocks go
// in the above try block to determine exactly which step threw the
// exception
} finally
{
try
{
if (os!=null) os.close();
} catch (IOException ioe)
{
// Fine... but let's try to free up any system resources which we used
if (bos!=null) bos.close();
throw ioe;
}
}
The only reason I concern myself with this is that I could easily see a program attempting the same operation a couple hundred times during its execution... and if it isn't really cycling any memory, the garbage collector might take its sweet time to clean things up. This means that I might be holding quite a lot of system resources by not addressing the problem.
tvynra at 2007-7-13 22:57:45 >
