The finalize()
method is only called when the object is destroyed and finalized by the GC, which happens at some undefined point in time after the last reference to the object is discarded. If the object is never released (e.g. you still have a reference to it), then finalize()
is never called.
Also bear in mind you have no control over when finalize()
is called, or if it will ever even be called at all. See general description of Object.finalize()
.
Even System.gc()
is not guaranteed to force the GC to do anything. It is only a suggestion to the JVM. See general description of System.gc()
In general, if you find yourself attempting to manipulate the GC like this in order to perform these types of checks, there are generally better ways. This is an inappropriate use of finalize()
and the GC.
For example, if you're trying to check if a presumed condition is true, consider using assert
in appropriate places (but be forewarned: assert
is not a replacement for a functional if
; it is merely to self-document and test conditions assumed at design time).
If part of your application's higher level functionality is to verify that a condition is true before exiting, then you should explicitly verify that the condition is true before exiting, e.g. in your case:
public static void main(String[] args)
{
Tank tank=new Tank();
tank.fill();
// check explicitly before terminating
if (!tank.empty())
System.err.println("Warning: Ending with non-empty tank!");
}
An explicit check gives you full control over when it happens in addition to the ability to attempt a recovery from the error.
Update: Another good option, which MadProgrammer helpfully brought up in the comments below, is to use a shutdown hook, if that's appropriate for you. That will provide a clean way to exit code on shutdown if your application has multiple exit points that you can't otherwise eliminate or control.
For more complex applications, by the way, you will find testing strategies such as unit testing, etc., when combined with good modular design (e.g. clearly defined preconditions, postconditions, invariants), can provide complete tests of application logic without requiring self-testing to be part of the normal run of the application. Not that there's anything wrong with the latter, especially in simple applications, but it is something you may be interested in finding out about for future reference.