The assumption that “you have the finalize()
block that should close all native resources when the GC gets to it” is wrong in the first place. There is no guaranty that every object representing a native resource has such a finalize()
method.
Second, a resource isn’t necessarily a native
resource.
When you have, e.g. a BufferedOutputStream
, an ObjectOutputStream
, or a ZipOutputStream
wrapping a FileOutputStream
, the latter likely has a finalize()
method to free the underlying native resource (that’s implementation dependent), but that doesn’t write any pending data of the wrapper stream needed to have correctly written data. Closing the wrapper stream is mandatory to ensure that the written output is complete.
Naively adding a finalize()
method to these wrapper stream classes to close them would not work. When the stream object gets collected, it implies that there is no reference to it, in other words there is no directed application→wrapper stream→native stream graph anymore. Since object graphs could be cyclic, there is no guaranty that an expensive search for an order among dead objects would succeed, and that’s why the JVM doesn’t even try.
Or, as the specification puts it:
The Java programming language imposes no ordering on finalize
method calls. Finalizers may be called in any order, or even concurrently.
Therefore, a finalize()
method of a wrapper would not be guaranteed to be called before the finalize()
method of underlying native stream, thus, the underlying native stream might have been finalized and closed before the wrapper stream making it impossible to write the pending data.
And the rabbit hole goes even deeper. Object instances are maintained by the JVM as needed by the code, but the code can get optimized to use encapsulated data directly. If the wrapper stream class had a finalize()
method, you might find out that the wrapper instance can be freed even earlier than expected, as discussed in finalize() called on strongly reachable object in Java 8.
Or, in short, explicit closing is the only way to ensure that it happens exactly at the right point of time.