Expensive resources should be reclaimed as soon as possible, by an
explict call to a clean-up method defined for this purpose. If this is
not done, then system performance can degrade.
In the worst cases, the system can even fail entirely.

Resources include:

input-output streams

database result sets, statements, and connections

threads

graphic resources

sockets

Resources which are created locally within a method must be cleaned up
within the same method, by calling a method appropriate to the resource
itself, such as close or dispose. (The exact name of the method
is arbitrary, but it usually has those conventional names.)
This is usually done automatically, using the
try-with-resources
feature, added in JDK 7.

If try-with-resources isn't available, then you need to clean up resources explicitly, by calling a clean-up
method in a finally clause.

For the case of a resource which is a field, however, there's more work to do:

implement a clean-up method which the user must call when finished with
the object, with a name such as close or dispose

the caller should be able to query an object to see if its clean-up method
has been executed

non-private methods (other than the clean-up method itself) should
throw an IllegalStateException if the clean-up method has already
been invoked

as a safety net, implement finalize to call the clean-up method
as well; if the user of the class neglects to call the clean-up method,
then this may allow recovery of the resource by the system

This example shows a class which retains a database connection during its
lifetime. (This example is artificial. Actually writing such a class would not seem necessary in practice,
since connection pools already perform such clean-up in the background.
It's used merely to demonstrate the ideas mentioned above.)

import java.sql.*;
import java.text.*;
import java.util.*;
/**
* This class has an enforced life cycle: after destroy is
* called, no useful method can be called on this object
* without throwing an IllegalStateException.
*/publicfinalclass DbConnection {
public DbConnection () {
//build a connection and assign it to a field
//elided.. fConnection = ConnectionPool.getInstance().getConnection();
}
/**
* Ensure the resources of this object are cleaned up in an orderly manner.
*
* The user of this class must call destroy when finished with
* the object. Calling destroy a second time is permitted, but is
* a no-operation.
*/publicvoid destroy() throws SQLException {
if (fIsDestroyed) {
return;
}
else{
if (fConnection != null) fConnection.close();
fConnection = null;
//flag that destory has been called, and that
//no further calls on this object are valid
fIsDestroyed = true;
}
}
/**
* Fetches something from the db.
*
* This is an example of a non-private method which must ensure that
* <code>destroy</code> has not yet been called
* before proceeding with execution.
*/synchronizedpublic Object fetchBlah(String aId) throws SQLException {
validatePlaceInLifeCycle();
//..elided
returnnull;
}
/**
* If the user fails to call <code>destroy</code>, then implementing
* finalize will act as a safety net, but this is not foolproof.
*/protectedvoid finalize() throws Throwable{
try{
destroy();
}
finally{
super.finalize();
}
}
/**
* Allow the user to determine if <code>destroy</code> has been called.
*/publicboolean isDestoyed() {
return fIsDestroyed;
}
// PRIVATE
/**
* Connection which is constructed and managed by this object.
* The user of this class must call destroy in order to release this
* Connection resource.
*/private Connection fConnection;
/**
* This object has a specific "life cycle", such that methods must be called
* in the order: others + destroy. fIsDestroyed keeps track of the lifecycle,
* and non-private methods must check this value at the start of execution.
* If destroy is called more than once, a no-operation occurs.
*/privateboolean fIsDestroyed;
/**
* Once <code>destroy</code> has been called, the services of this class
* are no longer available.
*
* @throws IllegalStateException if <code>destroy</code> has
* already been called.
*/privatevoid validatePlaceInLifeCycle(){
if (fIsDestroyed) {
String message = "Method cannot be called after destroy has been called.";
thrownew IllegalStateException(message);
}
}
}