- Understanding The finalize() Method In Java
- When To Use The finalize() Method In Java?
- How To Override The finalize() Method?
- Working Of The finalize() Method In Different Scenarios
- Handling Exceptions In finalize() Method
- Alternatives To The Finalize() Method In Java
- Conclusion
- Frequently Asked Questions
Finalize() Method In Java | Use Cases & Alternatives (+Examples)
In Java, memory management is largely handled by the garbage collector, which automatically deallocates memory used by objects no longer in use. However, there might be situations where an object needs to perform some cleanup before it gets removed from memory, like closing a file stream or releasing a network connection. This is where the finalize() method comes into play.
The finalize() method provides a mechanism for performing final operations before an object is garbage collected. Although its use has significantly declined with the introduction of better resource management techniques (like try-with-resources), understanding finalize() is still important from a historical and interview perspective.
In this article, we’ll explore how the finalize() method works, when and why it is invoked, its limitations, and why it's considered obsolete in modern Java development.
Understanding The finalize() Method In Java
The finalize() method in Java programming is a special method defined in the Object class. It is called by the garbage collector before an object is removed from memory. Think of it like a "clean-up crew" that gets one last chance to perform actions such as:
- Closing files
- Releasing network connections
- Cleaning up resources that the garbage collector doesn't handle
However, remember that it's not guaranteed to run every time, and you should not rely on it for important cleanup tasks.
Syntax Of finalize() Method
protected void finalize() throws Throwable {
// clean-up code here
super.finalize(); // optional, calls the parent class's finalize
}
Here:
- protected: It limits access to the class itself and subclasses (as defined in Object class)
- void: No return value
- finalize(): The method name; it's called by the garbage collector
- throws Throwable: It declares that it can throw any exception (checked or unchecked)
- super.finalize() (Optional): It calls the finalize method of the parent class for proper cleanup
Parameters Of finalize() Method:
The finalize() method takes no parameters and is declared protected to restrict access to the garbage collector or subclasses.
Return Value Of finalize() Method:
The finalize() method has a void return type and does not return any value.
Also Read: Final, Finally & Finalize In Java | 15+ Differences With Examples
When To Use The finalize() Method In Java?
Here are all the use cases where the finalize() method was used or considered relevant in Java, especially in earlier versions:
- As a Last Resort for Cleanup (Legacy Use): It was used as a backup to clean up resources like file handles or network connections when the programmer forgot to do so manually.
- Native Resource Release: Used to release memory or resources allocated outside the JVM (e.g., C/C++ code via JNI) that the garbage collector cannot manage.
- Object Lifecycle Logging: Used to log or print messages to track when objects are garbage collected, mainly for debugging or educational purposes.
- Freeing Up System Resources: When large objects hold onto limited resources (e.g., memory buffers or open handles), finalize() was used to ensure they are released eventually.
- Legacy Code Support: Found in older Java applications written before modern techniques like try-with-resources and AutoCloseable were available.
- Soft Error Recovery: In rare cases, used to attempt cleanup or soft recovery from an error that caused an object to be abandoned before being fully initialized or closed.
- Custom Cleanup Logic: Allowed defining custom logic to execute just before an object is removed from memory, such as notifying other objects or saving partial state.
How To Override The finalize() Method?
In Java, every class inherits the finalize() method from the Object class. We can override this method in our class if we want to perform any clean-up actions before the object is garbage collected.
Syntax:
@Override
protected void finalize() throws Throwable {
// cleanup code here
super.finalize(); // optional but good practice
}
Here:
- @Override: Tells the compiler we're overriding the method from the parent class.
- protected: Access modifier required by Java for this method.
- void finalize(): Method name, returns nothing.
- throws Throwable: Allows this method to throw exceptions.
- super.finalize(): Calls the parent class’s cleanup, if needed.
Code Example:
class MyClass {
int id;
MyClass(int id) {
this.id = id;
}
@Override
protected void finalize() throws Throwable {
System.out.println("Finalize called for object with id: " + id);
super.finalize(); // always good to call parent finalize
}
}
public class Main {
public static void main(String[] args) {
MyClass obj1 = new MyClass(101);
MyClass obj2 = new MyClass(102);
obj1 = null;
obj2 = null;
// Requesting garbage collection
System.gc();
System.out.println("Main method complete");
}
}
Y2xhc3MgTXlDbGFzcyB7CiAgICBpbnQgaWQ7CgogICAgTXlDbGFzcyhpbnQgaWQpIHsKICAgICAgICB0aGlzLmlkID0gaWQ7CiAgICB9CgogICAgQE92ZXJyaWRlCiAgICBwcm90ZWN0ZWQgdm9pZCBmaW5hbGl6ZSgpIHRocm93cyBUaHJvd2FibGUgewogICAgICAgIFN5c3RlbS5vdXQucHJpbnRsbigiRmluYWxpemUgY2FsbGVkIGZvciBvYmplY3Qgd2l0aCBpZDogIiArIGlkKTsKICAgICAgICBzdXBlci5maW5hbGl6ZSgpOyAvLyBhbHdheXMgZ29vZCB0byBjYWxsIHBhcmVudCBmaW5hbGl6ZQogICAgfQp9CgpwdWJsaWMgY2xhc3MgTWFpbiB7CiAgICBwdWJsaWMgc3RhdGljIHZvaWQgbWFpbihTdHJpbmdbXSBhcmdzKSB7CiAgICAgICAgTXlDbGFzcyBvYmoxID0gbmV3IE15Q2xhc3MoMTAxKTsKICAgICAgICBNeUNsYXNzIG9iajIgPSBuZXcgTXlDbGFzcygxMDIpOwoKICAgICAgICBvYmoxID0gbnVsbDsKICAgICAgICBvYmoyID0gbnVsbDsKCiAgICAgICAgLy8gUmVxdWVzdGluZyBnYXJiYWdlIGNvbGxlY3Rpb24KICAgICAgICBTeXN0ZW0uZ2MoKTsKCiAgICAgICAgU3lzdGVtLm91dC5wcmludGxuKCJNYWluIG1ldGhvZCBjb21wbGV0ZSIpOwogICAgfQp9Cg==
Expected Output:
Main method complete
Finalize called for object with id: 101
Finalize called for object with id: 102
(Note: The order or timing of finalize() messages may vary or may not appear at all, depending on the JVM.)
Explanation:
In the above code example-
- We first create a class MyClass with an id field to identify objects.
- We then override the finalize() method to print a message when the object is about to be garbage collected.
- In the main method, we create two objects and then set them to null, making them eligible for garbage collection.
- Next, we use System.gc() to request the garbage collector to run (although it is not guaranteed).
- When the garbage collector runs, it calls our overridden finalize() method before deleting the objects.
- Finally, we include a print statement inside finalize() to confirm when the method is called.
Working Of The finalize() Method In Different Scenarios
The behavior of the finalize() method in Java can vary based on whether it's overridden and how it's implemented. While the method provides a way to perform clean-up actions before an object is garbage collected, its execution depends on different scenarios. Let's explore how finalize() works in three specific cases to better understand its role and limitations.
Case 1: Object Is Garbage Collected, But No finalize() Method Is Defined
If a class doesn't override the finalize() method, the default version from the Object class is used. This default method doesn't perform any action, so garbage collection occurs silently without custom cleanup.
Code Example:
class MyClass {
int id;
MyClass(int id) {
this.id = id;
}
}
public class Main {
public static void main(String[] args) {
MyClass obj = new MyClass(1);
obj = null;
System.gc();
System.out.println("Main method finished");
}
}
Y2xhc3MgTXlDbGFzcyB7CiAgICBpbnQgaWQ7CgogICAgTXlDbGFzcyhpbnQgaWQpIHsKICAgICAgICB0aGlzLmlkID0gaWQ7CiAgICB9Cn0KCnB1YmxpYyBjbGFzcyBNYWluIHsKICAgIHB1YmxpYyBzdGF0aWMgdm9pZCBtYWluKFN0cmluZ1tdIGFyZ3MpIHsKICAgICAgICBNeUNsYXNzIG9iaiA9IG5ldyBNeUNsYXNzKDEpOwogICAgICAgIG9iaiA9IG51bGw7CgogICAgICAgIFN5c3RlbS5nYygpOwogICAgICAgIFN5c3RlbS5vdXQucHJpbnRsbigiTWFpbiBtZXRob2QgZmluaXNoZWQiKTsKICAgIH0KfQo=
Output:
Main method finished
Explanation:
In the above code example-
- We defined a simple class MyClass with an id.
- We created an object of MyClass and then set it to null, making it eligible for garbage collection.
- Since we didn't override finalize(), the JVM used the default version which does nothing.
- So, when System.gc() is called, no message or cleanup action is performed — the object is silently collected.
Case 2: Object Is Garbage Collected, And A finalize() Method Is Defined
When we override the finalize() method in a class, the JVM calls it before garbage collecting the object. This lets us run custom code (like printing a message or releasing resources).
Code Example:
class MyClass {
int id;
MyClass(int id) {
this.id = id;
}
@Override
protected void finalize() throws Throwable {
System.out.println("finalize() called for object with id: " + id);
}
}
public class Main {
public static void main(String[] args) {
MyClass obj = new MyClass(2);
obj = null;
System.gc();
System.out.println("Main method finished");
}
}
Y2xhc3MgTXlDbGFzcyB7CiAgICBpbnQgaWQ7CgogICAgTXlDbGFzcyhpbnQgaWQpIHsKICAgICAgICB0aGlzLmlkID0gaWQ7CiAgICB9CgogICAgQE92ZXJyaWRlCiAgICBwcm90ZWN0ZWQgdm9pZCBmaW5hbGl6ZSgpIHRocm93cyBUaHJvd2FibGUgewogICAgICAgIFN5c3RlbS5vdXQucHJpbnRsbigiZmluYWxpemUoKSBjYWxsZWQgZm9yIG9iamVjdCB3aXRoIGlkOiAiICsgaWQpOwogICAgfQp9CgpwdWJsaWMgY2xhc3MgTWFpbiB7CiAgICBwdWJsaWMgc3RhdGljIHZvaWQgbWFpbihTdHJpbmdbXSBhcmdzKSB7CiAgICAgICAgTXlDbGFzcyBvYmogPSBuZXcgTXlDbGFzcygyKTsKICAgICAgICBvYmogPSBudWxsOwoKICAgICAgICBTeXN0ZW0uZ2MoKTsKICAgICAgICBTeXN0ZW0ub3V0LnByaW50bG4oIk1haW4gbWV0aG9kIGZpbmlzaGVkIik7CiAgICB9Cn0K
Output:
Main method finished
finalize() called for object with id: 2
Explanation:
In the above code example-
- Here, we override the finalize() method to print a message.
- After creating the object and setting it to null, we called System.gc() to request garbage collection.
- Before the JVM deletes the object, it calls the overridden finalize() method and prints the message.
- The line "Main method finished" may appear before or after the finalize() message depending on JVM behavior - the call to System.gc() is just a suggestion, not a command.
Case 3: Exception In finalize() Method
If an exception occurs in the finalize() method, the JVM catches it silently. The exception doesn’t stop garbage collection, and the program continues without interruption.
Code Example:
class MyClass {
@Override
protected void finalize() throws Throwable {
System.out.println("Inside finalize()");
throw new Exception("Exception in finalize()");
}
}
public class Main {
public static void main(String[] args) {
MyClass obj = new MyClass();
obj = null;
System.gc();
System.out.println("Main method finished");
}
}
Y2xhc3MgTXlDbGFzcyB7CiAgICBAT3ZlcnJpZGUKICAgIHByb3RlY3RlZCB2b2lkIGZpbmFsaXplKCkgdGhyb3dzIFRocm93YWJsZSB7CiAgICAgICAgU3lzdGVtLm91dC5wcmludGxuKCJJbnNpZGUgZmluYWxpemUoKSIpOwogICAgICAgIHRocm93IG5ldyBFeGNlcHRpb24oIkV4Y2VwdGlvbiBpbiBmaW5hbGl6ZSgpIik7CiAgICB9Cn0KCnB1YmxpYyBjbGFzcyBNYWluIHsKICAgIHB1YmxpYyBzdGF0aWMgdm9pZCBtYWluKFN0cmluZ1tdIGFyZ3MpIHsKICAgICAgICBNeUNsYXNzIG9iaiA9IG5ldyBNeUNsYXNzKCk7CiAgICAgICAgb2JqID0gbnVsbDsKCiAgICAgICAgU3lzdGVtLmdjKCk7CiAgICAgICAgU3lzdGVtLm91dC5wcmludGxuKCJNYWluIG1ldGhvZCBmaW5pc2hlZCIpOwogICAgfQp9Cg==
Output:
Main method finished
Inside finalize()
Explanation:
In the above code example-
- We override finalize() and deliberately throw an exception inside it.
- After making the object eligible for garbage collection and calling System.gc(), the JVM called our finalize() method.
- The message inside finalize() was printed, but the exception did not crash the program.
- This shows that exceptions inside finalize() are silently ignored, and garbage collection continues.
Handling Exceptions In finalize() Method
In Java, if an exception is thrown inside the finalize() method, it is silently caught and ignored by the JVM. This means that the exception will not propagate, and the program will continue to run without any visible error or interruption. The garbage collector still proceeds with reclaiming the object’s memory, even if an error occurred during finalization. This behavior makes it unsafe to rely on finalize() for critical cleanup or resource management, as any failure inside the method goes unnoticed. For this reason, it's recommended to handle all exceptions explicitly within the finalize() method using try-catch blocks if it’s ever used, though modern Java encourages better alternatives like try-with-resources and AutoCloseable.
Alternatives To The Finalize() Method In Java
Here are some alternatives to using the finalize() method:
- Use try-with-resources to automatically close resources like files and streams.
- Implement the AutoCloseable or Closeable interface to define a close() method for custom cleanup.
- Create a manual cleanup() or dispose() method and call it explicitly when needed.
- Use PhantomReference with ReferenceQueue` for advanced post-garbage collection cleanup.
- Prefer these methods over finalize() as they offer better control and reliability.
Conclusion
The finalize() method in Java was once used as a mechanism to perform cleanup operations before an object is garbage collected. While it provided a way to release resources or log object destruction, it came with significant limitations—unpredictable execution, silent failure of exceptions, and performance overhead. With the introduction of more reliable and controlled alternatives like try-with-resources, AutoCloseable, and manual cleanup methods, finalize() has become obsolete. In fact, it has been deprecated in Java 9 and removed in Java 18. For modern Java development, it's best to avoid using finalize() and rely on safer, more predictable resource management techniques.
Frequently Asked Questions
Q. What is the purpose of the finalize() method in Java?
The finalize() method was used to perform cleanup operations before an object is garbage collected, such as releasing resources like file handles or network connections.
Q. Is the finalize() method guaranteed to be called before an object is destroyed?
No, the JVM does not guarantee that the finalize() method will be called. The garbage collector may choose to skip it, and it might not run at all before the program exits.
Q. Why is the finalize() method deprecated in Java?
It is deprecated because it is unreliable, can cause performance issues, and has better alternatives like try-with-resources and AutoCloseable that provide more predictable resource management.
Q. Can exceptions thrown in the finalize() method stop garbage collection?
No, any exception thrown inside finalize() is silently ignored by the JVM, and it does not stop the object from being garbage collected.
Q. What are the modern alternatives to finalize() in Java?
The most common alternatives include using try-with-resources, implementing the AutoCloseable or Closeable interface, and using explicit cleanup methods like close() or dispose().
Here are a few other topics that you might be interested in reading:
- 15 Popular JAVA Frameworks Use In 2023
- What Is Scalability Testing? How Do You Test Application Scalability?
- Top 50+ Java Collections Interview Questions
- 10 Best Books On Java In 2024 For Successful Coders
- Difference Between Java And JavaScript Explained In Detail
- Top 15+ Difference Between C++ And Java Explained! (+Similarities)
I’m a Computer Science graduate with a knack for creative ventures. Through content at Unstop, I am trying to simplify complex tech concepts and make them fun. When I’m not decoding tech jargon, you’ll find me indulging in great food and then burning it out at the gym.
Login to continue reading
And access exclusive content, personalized recommendations, and career-boosting opportunities.
Subscribe
to our newsletter
Comments
Add comment