Streams should be closed explicitly using the pattern shown in @erickson's answer. Relying on finalization to close streams for you is a really bad idea:
Calling System.gc()
is expensive, especially since (if it does anything) to is likely to trigger a full garbage collection. That will cause every reference in every reachable object in your heap to be traced.
If you read the javadocs for System.gc()
you will see that it is only a "hint" to the JVM to run the GC. A JVM is free to ignore the hint ... which takes us to the next problem.
If you don't run the GC explicitly, it might be a long time until the GC runs. And even then, there's no guarantee that finalizers are run immediately.
In the mean time:
- all open files stay open, possibly preventing other applications using them
- any unwritten data in the streams remains unwritten
- your java application might even run into problems opening other streams do to running out of file descriptor slots.
And there's one last problem with relying on finalization to deal with output streams. If there is unflushed data in the stream when it is finalized, an output stream class will attempt to flush it. But this is all happening on a JVM internal thread, not one of your application's threads. So if the flush fails (e.g. because the file system is full), your application won't be able to catch the resulting exception, and therefore won't be able to report it ... or do anything to recover.
EDIT
Returning to the original question, it turns out that the BufferedOutputStream class does not override the default Object.finalize()
method. So that means that a BufferedOutputStrean is not flushed at all when it is garbage collected. Any unwritten data in the buffer will be lost.
That's yet another reason for closing your streams explicitly. Indeed, in this particular case, calling System.gc()
is not just bad practice; it is also likely to lead to loss of data.