Having said don't use finalizers, Bruce Eckel came up with a very good couple of exceptions in his book Thinking in Java. They're supposed to be used to free memory allocated by native calls to either C or C++ code. As C/C++ code does not have garbage collection, this allows us to call free() or delete() avoiding memory leaks.
Another use is to check that your objects are being freed when you're sure that they're ready to be freed and not in error. This is the premise of the 'termination condition'. In this example, we create class that's supposed to read part of a file, this is the ImpracticalFileHandler below:
class ImpracticalFileHandler {
/** Pick any old file for the test */
private static final String FILE_NAME = FILE_PATH + "\\wibble.txt";
private FileInputStream fis;
private boolean isFileOpen;
private String testName;
ImpracticalFileHandler(String testName) {
try {
this.testName = testName;
fis = new FileInputStream(FILE_NAME);
isFileOpen = true;
} catch (Exception e) {
e.printStackTrace();
}
}
void readSectionOfFile() {
try {
// This doesn't so anything except discard what it reads
byte[] b = new byte[30];
fis.read(b);
} catch (Exception e) {
e.printStackTrace();
}
}
/** Close the file - Don't call this in Example 2 */
void closeFile() {
try {
fis.close();
} catch (Exception e) {
// Catch all exception and display a message
e.printStackTrace();
} finally {
isFileOpen = false;
}
}
@Override
protected void finalize() {
if (isFileOpen)
System.out.println(testName + " Error - You've left the file open");
}
}
To demonstrate the finalizer, create two instances of this class, and read some of the file. In the first instance, DO NOT call the closeFile() method, leave the file open. Only close the file for the second instance.
public static void main(String[] args) {
// EXAMPLE 1 - This should create an error message
ImpracticalFileHandler test = new ImpracticalFileHandler("Example 1");
// Do something with the file.
test.readSectionOfFile();
test = null; // drop the reference
// EXAMPLE 2 - This won't create an error message
test = new ImpracticalFileHandler("Example 2");
// Do something with the file.
test.readSectionOfFile();
test.closeFile(); // tidy up correctly
test = null; // drop the reference
// Ask the system to collect garbage - it may ignore us
// We should get one message if all goes well
System.gc();
}
In running this example, the message may, or may not, be printed as System.gc() isn’t guaranteed to run the garbage collector when asked. I find that System.gc() is called when you step through the code using the eclipse debugger.
This is a somewhat artificial example as, yes, I know that FileInputStream has a finalize() method to close the file automatically if the programmer forgets, but it proves that the finalize method does do something.
No comments:
Post a comment