Finalize Method in Java – A Comprehensive Guide with Examples

Updated on July 31, 2024

Article Outline

One of the most important aspects of Java programming is managing resources efficiently. Countless times, we have situations where we want to ensure that our resources—be they files, databases, or network connections—are cleaned up properly.

 

Ever wondered how Java handles cleanup before destroying objects? Many of us worry about managing resources effectively when objects are no longer needed, ensuring no memory leaks, and keeping our applications efficient.

 

This is where the finalize method in Java comes into play.

 

The finalize method in Java gives a way of doing cleanup work prior to the object’s destruction via the garbage collector. While in Java we have a garbage collector that takes care of deletion and every other thing related to memory, there are times when we have to force it and ensure that a certain resource is freed from memory.

 

The finalize method provides the user an opportunity to include extra code which runs right before the garbage collector collects an object. Thus, studying the finalize method, its usage and applicability will be of benefit in making more reliable and quality Java applications.

 

In this article, we will go through the basic concept of the finalize method in Java, its syntax, and when and how it is used with real-life examples.

The Role of Garbage Collection in Java

Simply put, garbage collection in Java is like having a tireless housekeeper. It avails memory space by freeing up objects which have been used in programs but are no longer needed. This makes our programs clean and avoids suffering from memory leaks.

 

However, how does this process actually work?

 

When objects are created in the Java program, they occupy some amount of memory. Once the use of these objects is over, the garbage collector plays its role in freeing this memory.

 

The finalize method executes before garbage collecting an object. This gives us an opportunity to free all resources like closing files or releasing memory.

*Image
Get curriculum highlights, career paths, industry insights and accelerate your technology journey.
Download brochure

Syntax and Basic Usage of the Finalize Method

Let’s look at how we can use the finalize method in Java. Here’s the basic syntax:

protected void finalize() throws Throwable { // Cleanup code here }

The protected keyword ensures that only the class itself or subclasses can access this method. The throws Throwable clause indicates that the method can throw any type of exception.

 

Example:

public class FinalizeExample { @Override protected void finalize() throws Throwable { System.out.println("Finalize method called"); // Cleanup code } public static void main(String[] args) { FinalizeExample obj = new FinalizeExample(); obj = null; System.gc(); // Requesting garbage collection } }

Output:

output

In this example, the finalize method is overridden to print a message. The finalize method is called when the object becomes eligible for garbage collection.

How the Finalize Method Works with Garbage Collection

Understanding how the finalize method works with garbage collection will help us use it better. When an object is not referenced anymore, it is eligible for Garbage Collection. Here is what happens in the step-by-step process:

 

  1. Object Creation: An object is created with the help of the new keyword.
  2. Object Becomes Unreferenced: All references to the object are now lost, and it is then garbage collected.
  3. Garbage Collector Invokes Finalize: Before the actual destruction of an object, the garbage collector invokes the finalize method.
  4. Resource Cleanup: Now the finalize method gets a chance to execute, letting us release resources.
  5. Object Destruction: The object is destroyed by the garbage collector, and memory is reclaimed.

 

Example:

import java.util.Scanner; public class UserInputFinalizeExample { private String resource; public UserInputFinalizeExample(String resource) { this.resource = resource; } @Override protected void finalize() throws Throwable { System.out.println("Cleaning up resource: " + resource); // Simulate resource cleanup } public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.println("Enter a resource name:"); String resourceName = scanner.nextLine(); UserInputFinalizeExample obj = new UserInputFinalizeExample(resourceName); obj = null; System.gc(); // Requesting garbage collection } }

Output:

output

In this example, we create an object using user input. When the object becomes eligible for garbage collection, the finalize method prints a cleanup message.

Scenarios Where the Finalize Method is Applicable

When should we use the finalize method in Java? This is a common question for many developers. We often need to ensure resources are released properly. The finalize method can help in certain scenarios.

Releasing System-Level Resources

Sometimes, our objects use system resources like file handles or sockets. If these resources are not released, it can lead to resource leaks. Using the finalize method, we can ensure these resources are freed up.

 

Example:

import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; public class FileHandler { private FileInputStream file; public FileHandler(String fileName) throws FileNotFoundException { file = new FileInputStream(fileName); } @Override protected void finalize() throws Throwable { if (file != null) { file.close(); System.out.println("File resource cleaned up."); } } public static void main(String[] args) throws FileNotFoundException { FileHandler handler = new FileHandler("example.txt"); handler = null; System.gc(); } }

Output:

output

Managing Database Connections

Database connections are another critical resource. We must ensure connections are closed properly to avoid database connection leaks.

 

Example:

import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class DatabaseConnection { private Connection connection; public DatabaseConnection(String dbUrl, String user, String password) throws SQLException { try { // Load the MySQL JDBC driver Class.forName("com.mysql.cj.jdbc.Driver"); connection = DriverManager.getConnection(dbUrl, user, password); } catch (ClassNotFoundException e) { System.out.println("MySQL JDBC Driver not found. Include it in your library path."); e.printStackTrace(); } catch (SQLException e) { System.out.println("Connection failed. Check output console."); e.printStackTrace(); } } @Override protected void finalize() throws Throwable { if (connection != null && !connection.isClosed()) { connection.close(); System.out.println("Database connection closed."); } } public static void main(String[] args) { try { DatabaseConnection dbConn = new DatabaseConnection("jdbc:mysql://localhost:3306/testdb", "user", "password"); dbConn = null; System.gc(); } catch (SQLException e) { e.printStackTrace(); } } }

Output:

output

Overriding the Finalize Method in Java with Examples

Overriding the finalize method allows us to add custom cleanup code. Here’s how we can do it.

 

Steps to Override the Finalize Method:

 

  1. Declare the method with protected access.
  2. Add the @Override annotation.
  3. Include any cleanup code inside the method.

 

Example:

public class CustomCleanup { private String resource; public CustomCleanup(String resource) { this.resource = resource; } @Override protected void finalize() throws Throwable { System.out.println("Cleaning up resource: " + resource); } public static void main(String[] args) { CustomCleanup obj = new CustomCleanup("CustomResource"); obj = null; System.gc(); } }

Output:

output

Limitations and Risks of Using the Finalize Method

While the finalize method can be useful, it comes with limitations and risks.

 

Unpredictable Timing The exact time when finalize is called is not guaranteed. This unpredictability can cause issues, especially in time-sensitive applications.
Performance Overhead Finalization can add overhead to garbage collection. This can affect the performance of our application.
Risk of Uncaught Exceptions If an exception occurs in the finalize method, it can be ignored. This can lead to resources not being released properly.

 

Best Practices:

 

  • Avoid using finalize for critical resource management.
  • Use explicit resource management techniques like try-with-resources and close methods.
  • Always call super.finalize() if you override the finalize method.

 

Example Demonstrating Risks:

public class FinalizeRisks { @Override protected void finalize() throws Throwable { System.out.println("Finalize method called"); throw new Exception("Error in finalize"); } public static void main(String[] args) { try { FinalizeRisks obj = new FinalizeRisks(); obj = null; System.gc(); } catch (Exception e) { e.printStackTrace(); } } }

Output:

output

In this example, the exception thrown in finalize is ignored, highlighting the risk.

Best Practices for Resource Management in Java

Have you ever wondered if there’s a Java resource management technique that’s superior to the finalize method? Let’s explore some best practices to keep our applications running smoothly.

Use Try-with-Resources

Introduced in Java 7, this feature helps manage resources efficiently. It ensures that resources are closed automatically.

 

Example:

import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; public class TryWithResourcesExample { public static void main(String[] args) { try (BufferedReader reader = new BufferedReader(new FileReader("example.txt"))) { String line; while ((line = reader.readLine()) != null) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } } }

Output:

output

In this example, the BufferedReader is closed automatically when the try block exits.

Explicitly Close Resources

Always close resources like files and database connections. This prevents resource leaks.

 

Example:

import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class DatabaseConnection { private Connection connection; public DatabaseConnection(String dbUrl, String user, String password) throws SQLException { try { // Load the MySQL JDBC driver Class.forName("com.mysql.cj.jdbc.Driver"); connection = DriverManager.getConnection(dbUrl, user, password); } catch (ClassNotFoundException e) { System.out.println("MySQL JDBC Driver not found. Include it in your library path."); e.printStackTrace(); } catch (SQLException e) { System.out.println("Connection failed. Check output console."); e.printStackTrace(); } } @Override protected void finalize() throws Throwable { if (connection != null && !connection.isClosed()) { connection.close(); System.out.println("Database connection closed."); } } public static void main(String[] args) { try { DatabaseConnection dbConn = new DatabaseConnection("jdbc:mysql://localhost:3306/testdb", "user", "password"); dbConn = null; System.gc(); } catch (SQLException e) { e.printStackTrace(); } } }

Output:

output

Use Shutdown Hooks

A shutdown hook is a thread that runs when the JVM is shutting down. It guarantees that resources are appropriately cleaned up.

 

Example:

public class ShutdownHookExample { public static void main(String[] args) { Runtime.getRuntime().addShutdownHook(new Thread(() -> { System.out.println("Shutdown hook running"); // Cleanup code })); System.out.println("Application running"); } }

Output:

output

Avoid Using Finalize for Critical Tasks

The finalize method is not reliable for critical resource management. It’s better to use explicit resource management techniques.

Alternatives to the Finalize Method

Looking for alternatives to the finalize method? Here are some effective options.

Try-with-Resources

This is the best option for managing resources like files and database connections. It’s simple and ensures resources are closed automatically.

Reference Queues

When objects become unreachable, we may manage cleaning via reference queues.

 

Example:

import java.lang.ref.PhantomReference; import java.lang.ref.ReferenceQueue; public class ReferenceQueueExample { public static void main(String[] args) { ReferenceQueue<Object> refQueue = new ReferenceQueue<>(); PhantomReference<Object> phantomRef = new PhantomReference<>(new Object(), refQueue); System.out.println("Phantom reference created"); } }

Output:

output

Using Close Methods

Implement a close method to release resources.

 

Example:

public class ResourceHandler { public void close() { // Cleanup code System.out.println("Resource closed"); } public static void main(String[] args) { ResourceHandler handler = new ResourceHandler(); handler.close(); } }

Output:

output

Weak References

These are useful for caches, where objects can be collected as garbage when memory is low.

 

Example:

import java.lang.ref.WeakReference; public class WeakReferenceExample { public static void main(String[] args) { WeakReference<Object> weakRef = new WeakReference<>(new Object()); System.out.println("Weak reference created"); } }

Output:

output

Conclusion

In conclusion, the finalize method in Java can help with resource cleanup, but it comes with limitations. We should use it cautiously and prefer alternatives like try-with-resources, shutdown hooks, and explicit close methods.

 

These practices ensure our applications remain efficient and free of resource leaks. Remember, effective resource management is key to robust Java applications.

 

FAQs
  • The finalize method is called just before an object is destroyed by the garbage collector.
  • No, it’s not reliable. It’s better to use explicit resource management techniques like try-with-resources.
  • Try-with-resources, shutdown hooks, reference queues, and explicit close methods are great alternatives.
  • Try-with-resources ensures that resources are closed automatically at the end of the try block.
  • Weak references allow objects to be garbage collected when memory is low, useful for implementing caches.

Updated on July 31, 2024

Link
left dot patternright dot pattern

Programs tailored for your success

Popular

Management

Data Science

Finance

Technology

Future Tech

Upskill with expert articles

View all
Hero Vired logo
Hero Vired is a leading LearnTech company dedicated to offering cutting-edge programs in collaboration with top-tier global institutions. As part of the esteemed Hero Group, we are committed to revolutionizing the skill development landscape in India. Our programs, delivered by industry experts, are designed to empower professionals and students with the skills they need to thrive in today’s competitive job market.
Blogs
Reviews
Events
In the News
About Us
Contact us
Learning Hub
18003093939     ·     hello@herovired.com     ·    Whatsapp
Privacy policy and Terms of use

|

Sitemap

© 2024 Hero Vired. All rights reserved