Reputation: 2999
Alright, so I know that you should always close your streams and other native resources, but I am currently not sure why.
I see one reason for why and that is because of the limited amount of resources available and you want to release them as soon as you are done with them. But lets assume that your application doesn't use that many resources, then there shouldn't be a need to close the resource right?
Especially since you have the finalize()
block that should close all native resources when the GC gets to it.
Upvotes: 1
Views: 884
Reputation: 298153
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.
Upvotes: 1
Reputation: 272
Firstly finalize is never guaranteed to be called by the GC, so you cannot rely on it.
Secondly, in a real world application the amount of resources needed by your application changes, hence you shouldn't rely on assumptions and you should free up as many resources as you can to provide the best possible performance.
In my opinion the key words are performance, availability, scalability.
Upvotes: 1
Reputation: 140457
Simple: you always strive to do the right thing.
Building an application on assumptions such as "it doesn't use many resources" is a wrong approach. Instead: you focus on getting your logic right.
You see: the thing with real world application is: when they are helpful, they will be used. And as soon as you have users, you will be dealing with additional requirements. That results in you enhancing and maintaining your code. And as a result of that, any "compromise" that you made earlier on ("it's just a small thing, so who cares") has the potential to make such activities much harder than the ought be.
In other words: you should strive to build applications that are "correct". You don't write sloppy code because it "doesn't matter". Because you very often can not predict if your code doesn't become "important" at some point - and then your sins will come back biting you.
And no, finalize isn't the answer to anything ( see here ). You care about all resources that your code is using, and you carefully make sure that resources have a well defined life cycle.
Upvotes: 1
Reputation: 4307
As a Java developer, you have little control over when, or even if, finalizers are invoked. If your resources are in limited supply (database connections, for example), or create additional threads that have to be serviced, or hold locks, or use substantial memory, then you need to exercise control over when they are allocated and freed. It isn't always obvious what the implications are for keeping a resource allocated, and it's always safer to minimize the scope and duration of your resource usage, so far as the logic of the application allows.
Upvotes: 0