For working professionals
For fresh graduates
More
6. JDK in Java
7. C++ Vs Java
16. Java If-else
18. Loops in Java
20. For Loop in Java
45. Packages in Java
52. Java Collection
55. Generics In Java
56. Java Interfaces
59. Streams in Java
62. Thread in Java
66. Deadlock in Java
73. Applet in Java
74. Java Swing
75. Java Frameworks
77. JUnit Testing
80. Jar file in Java
81. Java Clean Code
85. Java 8 features
86. String in Java
92. HashMap in Java
97. Enum in Java
100. Hashcode in Java
104. Linked List in Java
108. Array Length in Java
110. Split in java
111. Map In Java
114. HashSet in Java
117. DateFormat in Java
120. Java List Size
121. Java APIs
127. Identifiers in Java
129. Set in Java
131. Try Catch in Java
132. Bubble Sort in Java
134. Queue in Java
141. Jagged Array in Java
143. Java String Format
144. Replace in Java
145. charAt() in Java
146. CompareTo in Java
150. parseInt in Java
152. Abstraction in Java
153. String Input in Java
155. instanceof in Java
156. Math Floor in Java
157. Selection Sort Java
158. int to char in Java
163. Deque in Java
171. Trim in Java
172. RxJava
173. Recursion in Java
174. HashSet Java
176. Square Root in Java
189. Javafx
The finalize method in Java plays a crucial role in resource management, though it has limitations every developer should understand. This guide explains what the finalize method is, how it works with garbage collection, and provides practical examples for real-world scenarios.
Curious about where Java can take you? Enroll in upGrad's Software Engineering course to unlock career opportunities in software development.
The finalize method in Java Programming is a special method that gets called before an object is garbage collected. It's designed to perform cleanup operations on objects before they're permanently removed from memory. The finalize method comes protected under the Object class with the signature:
protected void finalize() throws Throwable
This method gives objects one last chance to release resources that aren't automatically handled by the garbage collector, such as file handles, network connections, or database connections.
Take the next step in your career with IIIT-B’s Executive Diploma in Data Science & AI.
Before diving deeper into the finalize method, let's understand how garbage collection works in Java:
Java's garbage collector automatically reclaims memory occupied by objects that are no longer reachable or referenced. An object becomes eligible for garbage collection when:
Here's a simple example showing how objects become unreferenced:
public class GarbageCollectionExample {
public static void main(String[] args) {
// Creating an object
StringBuilder builder = new StringBuilder("Hello");
// Making the object unreferenced by assigning null
builder = null;
// Suggesting garbage collection (not guaranteed)
System.gc();
}
}
Output:
[No visible output unless finalize method is overridden]
When the reference builder is set to null, the StringBuilder object becomes eligible for garbage collection.
Want to integrate your Java skills with cloud and DevOps? Explore the Professional Certificate Program in Cloud Computing and DevOps to boost your backend and deployment expertise.
When the garbage collector determines an object is ready for collection, it doesn't immediately destroy it. Instead, the process works as follows:
Let's see this in action with a simple example:
public class FinalizeExample {
public static void main(String[] args) {
// Creating an object
DatabaseConnection connection = new DatabaseConnection();
// Using the connection
connection.connect();
// Making the object unreferenced
connection = null;
// Suggesting garbage collection
System.gc();
// Sleep to give GC time to run (for demonstration)
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class DatabaseConnection {
private boolean isConnected = false;
public void connect() {
System.out.println("Database connection established");
isConnected = true;
}
@Override
protected void finalize() throws Throwable {
try {
if (isConnected) {
System.out.println("Closing database connection in finalize method");
// Close the connection logic would go here
isConnected = false;
}
} finally {
super.finalize(); // Always call superclass finalize
}
}
}
Output:
Database connection established
Closing database connection in finalize method
This example demonstrates a database connection that uses the finalize method to ensure connections are closed before the object is garbage collected. When the reference is nullified and garbage collection runs, the finalize method executes and closes the connection.
Let's explore a practical scenario where the finalize method can be useful. Consider a file handling system:
public class FileResourceExample {
public static void main(String[] args) {
// Create a file handler
FileHandler handler = new FileHandler("important_data.txt");
// Use the handler
handler.writeData("This is important data");
// Forget to close the handler (common mistake)
handler = null; // Reference lost
// Force garbage collection (for demonstration)
System.gc();
System.runFinalization();
// Program continues...
System.out.println("Program continues execution...");
// Sleep to give time for finalization (for demonstration)
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class FileHandler {
private String filename;
private boolean fileOpen;
public FileHandler(String filename) {
this.filename = filename;
this.fileOpen = true;
System.out.println("File opened: " + filename);
}
public void writeData(String data) {
if (fileOpen) {
System.out.println("Writing to file: " + data);
// Actual file writing code would go here
}
}
public void closeFile() {
if (fileOpen) {
System.out.println("Explicitly closing file: " + filename);
fileOpen = false;
// Actual file closing code would go here
}
}
@Override
protected void finalize() throws Throwable {
try {
if (fileOpen) {
System.out.println("WARNING: File was not closed properly. Closing in finalize: " + filename);
fileOpen = false;
// Actual emergency file closing code would go here
}
} finally {
super.finalize();
}
}
}
Output:
File opened: important_data.txt
Writing to file: This is important data
Program continues execution...
WARNING: File was not closed properly. Closing in finalize: important_data.txt
In this real-world example, the FileHandler class manages file resources. If a developer forgets to close the file explicitly (a common oversight), the finalize method acts as a safety net to ensure the file is closed eventually. This helps prevent resource leaks in production systems.
These three similarly named concepts in Java serve different purposes:
Keyword/Method | Purpose |
final | A keyword used to restrict modification of variables, methods, and classes |
finally | A block used in exception handling that always executes regardless of whether an exception occurs |
finalize() | A method called by the garbage collector before reclaiming an object's memory |
The finalize method in Java should be used sparingly and for specific purposes:
Here's an example of using finalize as a safety net for a network connection:
public class NetworkResourceExample {
public static void main(String[] args) {
// Scenario: Code in a try-with-resources block (recommended approach)
try (NetworkConnection properConnection = new NetworkConnection("server1")) {
properConnection.sendData("Hello, server!");
} catch (Exception e) {
e.printStackTrace();
}
// Scenario: Improper connection handling (bad practice)
NetworkConnection improperConnection = new NetworkConnection("server2");
improperConnection.sendData("Hello again!");
// Developer forgot to close connection
// Force GC for demonstration
improperConnection = null;
System.gc();
// Wait to observe finalization
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class NetworkConnection implements AutoCloseable {
private String serverName;
private boolean connected;
public NetworkConnection(String serverName) {
this.serverName = serverName;
this.connected = true;
System.out.println("Connected to " + serverName);
}
public void sendData(String data) {
if (connected) {
System.out.println("Sending to " + serverName + ": " + data);
}
}
@Override
public void close() {
if (connected) {
System.out.println("Properly closing connection to " + serverName);
connected = false;
// Actual connection closure would happen here
}
}
@Override
protected void finalize() throws Throwable {
try {
if (connected) {
System.out.println("WARNING: Connection to " + serverName + " was not closed properly. Closing in finalize().");
connected = false;
// Emergency cleanup code
}
} finally {
super.finalize();
}
}
}
Output:
Connected to server1
Sending to server1: Hello, server!
Properly closing connection to server1
Connected to server2
Sending to server2: Hello again!
WARNING: Connection to server2 was not closed properly. Closing in finalize().
This example contrasts proper resource management using try-with-resources with improper resource management that relies on finalize as a backup. The finalize method catches the developer's mistake of not closing the connection.
To override the finalize method in Java, follow these steps:
Here's the proper way to override the finalize method:
public class CorrectFinalizeOverride {
private String resourceName;
private boolean resourceAcquired;
public CorrectFinalizeOverride(String name) {
this.resourceName = name;
this.resourceAcquired = true;
System.out.println("Resource acquired: " + resourceName);
}
// Proper way to release resources
public void release() {
if (resourceAcquired) {
System.out.println("Explicitly releasing: " + resourceName);
resourceAcquired = false;
}
}
// Correct finalize override pattern
@Override
protected void finalize() throws Throwable {
try {
// Perform cleanup
if (resourceAcquired) {
System.out.println("WARNING: Resource not released properly: " + resourceName);
resourceAcquired = false;
}
} finally {
// Always call super.finalize() in finally block
super.finalize();
}
}
public static void main(String[] args) {
// Case 1: Proper resource management
CorrectFinalizeOverride obj1 = new CorrectFinalizeOverride("Resource1");
obj1.release();
// Case 2: Improper resource management
CorrectFinalizeOverride obj2 = new CorrectFinalizeOverride("Resource2");
// forgot to release
// Make objects eligible for garbage collection
obj1 = null;
obj2 = null;
// Request garbage collection
System.gc();
System.runFinalization();
// Wait to observe finalization
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Output:
Resource acquired: Resource1
Explicitly releasing: Resource1
Resource acquired: Resource2
WARNING: Resource not released properly: Resource2
This example demonstrates the correct pattern for overriding the finalize method, ensuring proper cleanup even when developers forget to release resources explicitly.
Due to the limitations of the finalize method, Java has introduced better alternatives:
public class TryWithResourcesExample {
public static void main(String[] args) {
// Resources are automatically closed when the try block exits
try (FileOutputStream fos = new FileOutputStream("output.txt")) {
fos.write("Hello World".getBytes());
System.out.println("Data written to file");
} catch (IOException e) {
e.printStackTrace();
}
// FileOutputStream is automatically closed here
}
}
Output:
Data written to file
The try-with-resources approach automatically closes resources that implement AutoCloseable, eliminating the need for finalize.
import java.lang.ref.Cleaner;
public class CleanerExample {
// Create a cleaner
private static final Cleaner cleaner = Cleaner.create();
// Resource to be cleaned up
private static class ResourceHolder implements Runnable {
private String resourceName;
ResourceHolder(String name) {
this.resourceName = name;
System.out.println("Resource acquired: " + resourceName);
}
@Override
public void run() {
System.out.println("Cleaning up resource: " + resourceName);
// Actual cleanup code would go here
}
}
private final Cleaner.Cleanable cleanable;
private final ResourceHolder holder;
public CleanerExample(String name) {
this.holder = new ResourceHolder(name);
this.cleanable = cleaner.register(this, holder);
}
// Explicit cleanup method (preferred way)
public void close() {
cleanable.clean();
}
public static void main(String[] args) {
// Case 1: Proper resource management
CleanerExample resource1 = new CleanerExample("Resource1");
resource1.close(); // Explicitly clean
// Case 2: Relying on automatic cleaning
CleanerExample resource2 = new CleanerExample("Resource2");
// No explicit cleanup
// Make eligible for garbage collection
resource1 = null;
resource2 = null;
// Suggest garbage collection
System.gc();
// Wait to observe cleaning
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Output:
Resource acquired: Resource1
Cleaning up resource: Resource1
Resource acquired: Resource2
Cleaning up resource: Resource2
The Cleaner API provides a more reliable and efficient mechanism for resource cleanup compared to the finalize method.
No, final methods in Java cannot be overridden. The final keyword prevents a method from being overridden in subclasses, ensuring its implementation remains constant throughout the inheritance hierarchy.
public class FinalMethodExample {
// Final method that cannot be overridden
public final void displayMessage() {
System.out.println("This is a final method");
}
}
class ChildClass extends FinalMethodExample {
// This will cause a compilation error
// @Override
// public void displayMessage() {
// System.out.println("Trying to override final method");
// }
}
Yes, final methods in Java can be overloaded. Method overloading is about creating multiple methods with the same name but different parameters, which is allowed for final methods.
public class FinalMethodOverloadingExample {
// Final method with one parameter
public final void display(String message) {
System.out.println("String message: " + message);
}
// Overloaded final method with different parameter
public final void display(int number) {
System.out.println("Integer number: " + number);
}
public static void main(String[] args) {
FinalMethodOverloadingExample example = new FinalMethodOverloadingExample();
example.display("Hello"); // Calls first method
example.display(100); // Calls second method
}
}
Output:
String message: Hello
Integer number: 100
This example shows that final methods can be overloaded by changing the parameter list.
The finalize method in Java is like a safety net that catches resources before they're lost forever. It helps clean up things like open files and connections when programmers forget to do it themselves. But it's not reliable - it might run late or not at all.
Today's Java developers should use better tools like try-with-resources instead. Think of finalize as your backup plan, not your main strategy. When used correctly, it can help prevent resource leaks, but depending on it too much can cause more problems than it solves.
Always close your resources explicitly rather than hoping finalize will catch them. This makes your code safer, faster, and more predictable.
The finalize method in Java is a protected method of the Object class that is called by the garbage collector before reclaiming an object's memory, allowing for last-minute cleanup operations. It serves as the last opportunity for an object to release any system resources it might be holding before it's permanently removed from memory.
No, final methods in Java cannot be overridden. The final keyword prevents method overriding in subclasses. This restriction is enforced at compile-time, meaning any attempt to override a final method will result in a compilation error rather than a runtime exception.
Yes, final methods in Java can be overloaded by creating methods with the same name but different parameters. This is because method overloading is resolved at compile time based on method signatures, whereas the final keyword only restricts runtime polymorphism through method overriding.
The finalize method in Java is used to perform cleanup operations on objects before they're garbage collected, especially for resources not automatically managed by Java. It helps prevent resource leaks by providing a mechanism to release external resources like file handles, database connections, and network sockets that the garbage collector doesn't know how to clean up on its own.
The finalize method is called at most once per object by the JVM, even if the object is later resurrected. This is an important limitation to understand, as it means you cannot rely on finalize for repeated cleanup operations on the same object throughout its potentially complex lifecycle.
The finalize method was deprecated in Java 9 in favor of better alternatives like try-with-resources and the Cleaner API. The deprecation came after years of practical experience showed that finalize was problematic due to its unpredictable timing, performance impacts, and potential for introducing subtle bugs in applications.
Final is a keyword for constants, finally is an exception handling block, and finalize() is a method called before garbage collection. Though they sound similar, they serve completely different purposes in Java programming: final prevents modification, finally ensures code execution despite exceptions, and finalize helps with resource cleanup before memory reclamation.
If an exception occurs in the finalize method, it is ignored and finalization of that object terminates. This silent failure behavior makes debugging finalize-related issues challenging, as exceptions are swallowed by the runtime without any notification to the application, potentially masking serious problems.
Finalize can delay garbage collection by resurrecting the object, but cannot permanently prevent it. Object resurrection occurs when the finalize method creates new references to the object, temporarily saving it from garbage collection, but this only postpones rather than cancels the eventual memory reclamation process.
No, it's not recommended to rely on finalize for critical resource cleanup due to its unpredictable execution. Modern Java programming best practices strongly favor explicit resource management patterns such as try-with-resources, which provide deterministic cleanup with better performance characteristics and fewer potential pitfalls.
A final method in Java is a method that cannot be overridden by subclasses, ensuring its implementation remains constant throughout the inheritance hierarchy. Using the final keyword for methods is a common practice when the behavior defined in a method is essential to the class's proper functioning and altering it could break the class's contract or security guarantees.
Take the Free Quiz on Java
Answer quick questions and assess your Java knowledge
Author
Talk to our experts. We are available 7 days a week, 9 AM to 12 AM (midnight)
Indian Nationals
1800 210 2020
Foreign Nationals
+918068792934
1.The above statistics depend on various factors and individual results may vary. Past performance is no guarantee of future results.
2.The student assumes full responsibility for all expenses associated with visas, travel, & related costs. upGrad does not provide any a.