Why would you ever implement finalize()?
A simple rule: never use finalizers.
The fact alone that an object has a finalizer (regardless what code it executes) is enough to cause considerable overhead for garbage collection.
From an article by Brian Goetz:
Objects with finalizers (those that have a non-trivial finalize() method) have significant overhead compared to objects without finalizers, and should be used sparingly. Finalizeable objects are both slower to allocate and slower to collect. At allocation time, the JVM must register any finalizeable objects with the garbage collector, and (at least in the HotSpot JVM implementation) finalizeable objects must follow a slower allocation path than most other objects. Similarly, finalizeable objects are slower to collect, too. It takes at least two garbage collection cycles (in the best case) before a finalizeable object can be reclaimed, and the garbage collector has to do extra work to invoke the finalizer. The result is more time spent allocating and collecting objects and more pressure on the garbage collector, because the memory used by unreachable finalizeable objects is retained longer. Combine that with the fact that finalizers are not guaranteed to run in any predictable timeframe, or even at all, and you can see that there are relatively few situations for which finalization is the right tool to use.
You could use it as a backstop for an object holding an external resource (socket, file, etc). Implement a close()
method and document that it needs to be called.
Implement finalize()
to do the close()
processing if you detect it hasn't been done. Maybe with something dumped to stderr
to point out that you're cleaning up after a buggy caller.
It provides extra safety in an exceptional/buggy situation. Not every caller is going to do the correct try {} finally {}
stuff every time. Unfortunate, but true in most environments.
I agree that it's rarely needed. And as commenters point out, it comes with GC overhead. Only use if you need that "belt and suspenders" safety in a long-running app.
I see that as of Java 9, Object.finalize()
is deprecated! They point us to java.lang.ref.Cleaner
and java.lang.ref.PhantomReference
as alternatives.
finalize()
is a hint to the JVM that it might be nice to execute your code at an unspecified time. This is good when you want code to mysteriously fail to run.
Doing anything significant in finalizers (basically anything except logging) is also good in three situations:
- you want to gamble that other finalized objects will still be in a state that the rest of your program considers valid.
- you want to add lots of checking code to all the methods of all your classes that have a finalizer, to make sure they behave correctly after finalization.
- you want to accidentally resurrect finalized objects, and spend a lot of time trying to figure out why they don't work, and/or why they don't get finalized when they are eventually released.
If you think you need finalize(), sometimes what you really want is a phantom reference (which in the example given could hold a hard reference to a connection used by its referand, and close it after the phantom reference has been queued). This also has the property that it may mysteriously never run, but at least it can't call methods on or resurrect finalized objects. So it's just right for situations where you don't absolutely need to close that connection cleanly, but you'd quite like to, and the clients of your class can't or won't call close themselves (which is actually fair enough - what's the point of having a garbage collector at all if you design interfaces that require a specific action be taken prior to collection? That just puts us back in the days of malloc/free.)
Other times you need the resource you think you're managing to be more robust. For example, why do you need to close that connection? It must ultimately be based on some kind of I/O provided by the system (socket, file, whatever), so why can't you rely on the system to close it for you when the lowest level of resource is gced? If the server at the other end absolutely requires you to close the connection cleanly rather than just dropping the socket, then what's going to happen when someone trips over the power cable of the machine your code is running on, or the intervening network goes out?
Disclaimer: I've worked on a JVM implementation in the past. I hate finalizers.