Thursday, September 27, 2018

finalize() Method in Java

In Java when there are no more references to the object that object is eligible to be garbage collected. There may be a situation where an object needs to perform some action just before it is getting garbage collected. For example if an object is holding some non-java resources like file handle then it is better to make sure that these resources are closed before an object is garbage collected because simply reclaiming the memory used by an object would not guarantee that the resources it held would be released. For that purpose Java provides a mechanism called finalization through finalize() method. finalize method in Java is called by the garbage collector on an object for cleaning up resources just before the object is garbage collected.

General form of Java finalize() method

finalize method in Java is provided as a protected method in the Object class.

protected void finalize() throws Throwable

Just as a reminder the protected access modifier means - Variables, methods and constructors which are declared protected in a superclass can be accessed only by the subclasses in other package or any class within the package of the protected members' class.

Since all the classes have Object class as the super class either directly or indirectly so this method would be accessible to each and every class anyway so it makes sense to keep the access as protected.

When is finalize() method called in Java

As we know that in Java object memory deallocation happens automatically through garbage collection. In Java, garbage collector is run by the run time environment periodically and it looks for the objects for which there are no existing references. finalize method for an object is executed just before it is garbage collected. But here lies the caveat According to Java language specification - http://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.6 The Java programming language does not specify how soon a finalizer will be invoked that's one reason why we should not rely solely on finalize() method to release resources.

According to Joshua Bloch in his book Effective Java, Item 7: Avoid Finalizers

"The promptness with which finalizers are executed is primarily a function of the garbage collection algorithm, which varies widely from JVM implementation to JVM implementation. The behavior of a program that depends on the promptness of finalizer execution may likewise vary. It is entirely possible that such a program will run perfectly on the JVM on which you test it and then fail miserably on the JVM favored by your most important customer."

Note that finalize method is deprecated from Java 9 onwards. Reference- https://docs.oracle.com/javase/10/docs/api/java/lang/Object.html#finalize()

How to use finalize method in Java

The finalize method provided by root class Object performs no special action; it simply returns normally. Any class which needs some functionality to be provided in finalize() method has to override this definition and provide the functionality for cleanup.

According to Java docs- The finalize method may take any action, including making this object available again to other threads; the usual purpose of finalize, however, is to perform cleanup actions before the object is irrevocably discarded.

Java example for finalize() method

Here is a simple example where an object is created then that object reference is set as null. Also, System.gc() is called explicitly to run garbage collector. That should mean a call to finalize() method before the object is garbage collected. Note you may not get the output in some of the runs as System.gc() is more of a suggestion to the Java virtual machine to reclaim memory from unused objects, it may not run as soon as System.gc() is called and the program may terminate without calling the finalize method.

public class FinalizeDemo {
  int i;
  FinalizeDemo(int num){
    this.i = num;
  }
  public static void main(String[] args) {
    // creating object
    FinalizeDemo finalizeDemo = new FinalizeDemo(10);
    Temp temp = new Temp();
    // setting object reference as null so it is 
    // eligible for garabge collection
    finalizeDemo = null;
    temp.doCalcualtion();
    // setting object reference as null so it is 
    // eligible for garabge collection
    temp = null;
    // Calling System.gc() to run garbage collector
    System.gc();        
  }
    
  @Override
  protected void finalize() throws Throwable {
    try{
      System.out.println("finalize method called for FinalizeDemo");
    }finally{        
      super.finalize();
    }
  } 
}

class Temp{    
  public void doCalcualtion(){
    int i = 5;
    System.out.println("value of i is " + i);
  }
  @Override
  protected void finalize() throws Throwable {
    try{
      System.out.println("finalize method called for Temp");
    }finally{
      super.finalize();
    }
  }
}

Output

value of i is 5
finalize method called for Temp
finalize method called for FinalizeDemo

Though I have used System.gc here to some how make sure that finalize() method is indeed called but don't rely on it. To quote Joshua Bloch again "Don't be seduced by the methods System.gc and System.runFinalization. They may increase the odds of finalizers getting executed, but they don't guarantee it. The only methods that claim to guarantee finalization are System.runFinalizersOnExit and its evil twin, Runtime.runFinalizersOnExit. These methods are fatally flawed and have been deprecated."

How to properly write a finalize() method in Java

Like constructor chaining in Java there is no finalizer chaining so super class finalize method would not be called automatically.

As example- If there is a parent class A which provides a finalize method and child class B that extends class A and overrides finalize method. Then only Class B's finalize method will be called. Parent Class A's finalize method would not be called automatically. It has to be explicitly called using super. In that case class B's finalize method will look like-

protected void finalize() throws Throwable {
  try {
    // clean up
  } finally {
    super.finalize(); // call parent class’ finalize
  }
}

When can you use finalize method

Though there are other better alternatives to clean up resources like a finally block or try-with-resources(ARM) available from Java 7. But to make sure, just as an extra safety measure, that resources are indeed closed before the object is destroyed finalize() method may be used. But be forewarned it comes with a hit on performance.

Finalize method and exception handling

Any exception thrown by the finalize method while finalize method is executing causes the finalization of this object to be halted, but is otherwise ignored.

Points to Note

  1. Every class in Java inherits the finalize() method from java.lang.Object.
  2. finalize method in Java is called by the garbage collector when it determines no more references to the object exist.
  3. The finalize method of class Object performs no special action; it simply returns normally. Subclasses of Object may override this definition.
  4. If overridding finalize() method, it is a good programming practice to use a try-catch-finally statement and to always call super.finalize() as there is no concept of finalizer chaining.
  5. The finalize method is never invoked more than once by a Java virtual machine for any given object.
  6. finalize method is deperecated from Java 9.

That's all for this topic finalize() Method in Java. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Java Basics Tutorial Page


Related Topics

  1. final Vs finally Vs finalize in Java
  2. Constructor chaining in Java
  3. Association, Aggregation And Composition in Java
  4. super Keyword in Java With Examples
  5. Core Java Basics Interview Questions And Answers

You may also like-

  1. strictfp in Java
  2. Multi catch statement in Java 7
  3. interface static methods in Java 8
  4. Overriding hashCode() and equals() method in Java
  5. fail-fast Vs fail-safe iterator in Java
  6. Splitting a String - Java Program
  7. What if run() method called directly instead of start() method
  8. Difference between Thread and Process in Java

No comments:

Post a Comment