In this post, we will see what is the use of finalize() method in java. Although this post is part of garbage collection, we will discuss it with different scenarios.
Here is the table content of the article will we will cover this topic.
1. What is finalize() method in java?
2. What is a cleanup activity?
3. How does the finalize() method works with Garbage collection?
4. How to Override the finalize method?
5. How the finalize() method works in different scenarios?
6. The important point about the finalize() method?
7. Disadvantages or Reasons for not using finalize() method?
What is finalize() method in java?
The finalize() method is defined in the Object class which is the super most class in Java. This method is called the Garbage collector just before they destroy the object from memory. The Garbage collector is used to destroy the object which is eligible for garbage collection.
What is a cleanup activity?
Let’s say you want to perform some activities before destroying the object from memory. For example, You can close the resource associated with that object like Database Connection, or Network Connection. We will discuss it in detail later.
Let’s have a look at the code.
protected void finalize() throws Throwable { }
The finalize() method is a protected and non-static method of Object class. As you know Object is super most class and each class inherits the Object class, It means the finalize() method is available in each class.
How does the finalize() method works with Garbage collection?
The finalize() method is called by the garbage collector for an object when garbage collection determines that there are no more references to the object. The garbage collection determines each object of the class, if there is no reference for the object it means it should be destroyed.
Let’s understand with an example:
public class Example { public static void main(String[] args) { String string1 = "Hello"; string1 = null; } }
1. When String object string1 holds the value “Hello”. It means string1 is a reference of the String object.
2. When String object string1 holds the NULL. It means does not have any reference then it is eligible for garbage collection.
3. The Garbage collector makes a call to finalize() method to perform some activity before destroying the object.
How to Override the finalize method?
Now you know how the garbage collector works with garbage collection and finalize() method. So, let’s discuss the finalize() method. How we can override it? What we can do with it?
A subclass can override the finalize() method to dispose of system resources or to perform other cleanups. In this example, Data is a class and of course, it’s a subclass for the Object class.
public class Data { public static void main(String[] args) { Data obj = new Data(); obj = null; System.gc(); System.out.println("Done"); } @Override protected void finalize() { System.out.println("Before Destory the Object perform some activity"); System.out.println("Release connection"); System.out.println("Close network connection"); } }
Output: Done
Before Destory the Object perform some activity
Release connection
Close network connection
How the finalize() method works in different scenarios
1. Whose finalize() method is called
Let’s say you want to override the finalize() method of the Object class in the user-defined class.
public class Data { public static void main(String[] args) { String s = "Hello"; s = null; System.gc(); System.out.println("Garbage collector"); } @Override protected void finalize() { System.out.println("finilize() method called"); } }
Output: Garbage collector
As you can see the above program prints only “Garbage collector”. You must think about why it’s not printing the “finalize() method called”.
Because Garbage Collector makes a call to finalize() method of that class, whose object is eligible for Garbage collection. In the above example s = null; where ‘s’ is the object of the String class. So, the Garbage collector is called the finalize() method of the String class.
public class Data { public static void main(String[] args) { Data data = new Data(); data = null; System.gc(); System.out.println("Garbage collector"); } @Override protected void finalize() { System.out.println("finilize() method called"); } }
Output: Garbage collector
finilize() method called
2. Explicitly call to finalize() method
If we are calling finalize() method explicitly, Then JVM executes it as a normal method. It can’t destroy the object or not able to remove the object from memory. This method is useful only with Garbage Collector to release the memory.
public class Data { public static void main(String[] args) { Data data = new Data(); Data data1 = new Data(); data1 = null; // Explicit call data.finalize(); System.out.println("Garbage collector"); System.gc(); //Implicit call to finilize() method } @Override protected void finalize() { System.out.println("finilize() method called"); } }
Output: finilize() method called
Garbage collector
finilize() method called
In the above example when we are calling the finalize() method explicitly it is not destroying any object. But when System.gc() it makes an implicit call to finalize() method it destroys the object data1.
The important point about finalize() method
1. Whenever any object is eligible for garbage collection the garbage collector removes it from memory. Before removing it from memory, it makes a call to finalize() method of the Object class if you are not overriding the finalize() method. But If you are overriding finalize() method then it’s your responsibility to call finalize() method of the superclass(Object class).
NOTE: If you forgot to call the finalize() method of the superclass(Object class) then it will never be called.
Solution: It’s difficult to remember to call the finalize() method of the superclass. So, we should put the code in the finally block. So that whenever we are overriding the finalize() method the finally block takes care of finalize() method of the superclass.
public class Data { public static void main(String[] args) { Data obj = new Data(); obj = null; System.gc(); System.out.println("Done"); } @Override protected void finalize() throws Throwable { try { System.out.println("Before Destory the Object perform some activity"); System.out.println("Release connection"); System.out.println("Close network connection"); } catch (Throwable e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { super.finalize(); } } }
Output: Done
Before Destory the Object perform some activity
Release connection
Close network connection
2. The finalize() method is called only one time by the Garbage collector for an object. If the object is already reviving itself from finalize() method then it will not be called again.
Let’s understand with an example:
In this example, the Garbage collector is called two times by gc() method but the finalize() method is called only one time.
public class Data { public static void main(String[] args) { Data obj = new Data(); obj = null; System.gc(); System.out.println("Running garbage collector by gc() method"); System.gc(); System.out.println("Again try to run garbage collector by gc() method"); } @Override protected void finalize() { System.out.println("Finilized method is called"); } }
Output: Running garbage collector by gc() method
Finilized method is called
Again try to run garbage collector by gc() method
3. If any exception occurs in a finalize() method, then the exception is ignored by the garbage collector and it will not be propagated further.
public class Data { public static void main(String[] args) { Data obj = new Data(); obj = null; System.gc(); System.out.println("Running garbage collector by gc() method"); } @Override protected void finalize() { System.out.println("finalize method"); //Divide by zero excetion int a = 1/0; System.out.println("Finilized method is called"); } }
Output: finalize method
Running garbage collector by gc() method
NOTE: JVM ignores only unchecked exceptions while executing the finalize() method. We can provide the catch block for unchecked exceptions there then JVM executes the corresponding catch block.
public class Data { public static void main(String[] args) { Data obj = new Data(); obj = null; System.gc(); System.out.println("Running garbage collector by gc() method"); } @Override protected void finalize() { //Artmetic by zero excetion try { int a = 1/0; } catch(ArithmeticException e) { System.out.println("ArithmeticException Occured"); } System.out.println("Finilized method is called"); } }
Output: Running garbage collector by gc() method
ArithmeticException Occured
Finilized method is called
4. The JVM doesn’t make any guarantee about the time when the finalize() method is called. When we invoke System.gc() , then JVM makes invokes the Garbage collector to perform a clean-up activity. But JVM doesn’t guarantee that either the Garbage collector will work or not.
5. Whenever System.gc() is called it makes a request to JVM to execute the Garbage Collector. The JVM decides when to call Garbage Collector. Most probably the JVM calls Garbage Collector if there is less memory available in the Heap area or when the memory is low.
Disadvantages or Reasons for not using finalize() method
As you know finalize() method does not work in chaining like constructors. You must see when you call a constructor then it makes a call to the constructor of the superclass. The constructor makes implicitly calls to the constructor of the superclass.
But, the finalize() method doesn’t support the chaining and we need to call explicitly.
Let’s say if someone does not call super.finalize() in subclasses finalize() block, then super class’s finalize() will never be invoked anyhow.