DEV Community

Mohammed mhanna
Mohammed mhanna

Posted on

🚫Never Use finalize() in Java

Many Java developers have seen or even used the finalize() method at least once. It sounds like a convenient way to clean up resources before an object is destroyed, right?

Well... not anymore. ☠️

In modern Java, finalize() is deprecated, unreliable, and should never be used in new code. Let’s see why 👇


🧩 What Is finalize()?

In older versions of Java, you could override the finalize() method to perform cleanup tasks — like closing files or releasing system resources — before an object was garbage collected.

Example:

class MyFile {
    @Override
    protected void finalize() throws Throwable {
        System.out.println("Cleaning up resources...");
    }
}
Enter fullscreen mode Exit fullscreen mode

When the object becomes unreachable, the JVM might (eventually) call finalize() before garbage collecting it.

But there’s a big problem with this idea.


🚨 Why You Should Never Use finalize()
1️⃣ It’s Unpredictable

The JVM decides when or even if finalize() runs.
You have no guarantee that it will execute at all.

Example:

public class Main {
    public static void main(String[] args) {
        new MyFile();
        System.out.println("Program end");
    }
}

Enter fullscreen mode Exit fullscreen mode

Output might be:

Program end

Enter fullscreen mode Exit fullscreen mode

✅ Or sometimes:

Cleaning up resources...
Program end

Enter fullscreen mode Exit fullscreen mode

There’s no consistency — it depends entirely on the JVM.


2️⃣ It Causes Performance Issues

Objects with finalize() are more expensive to garbage collect.
They go through an extra GC phase (called finalization queue), which slows things down.

If many objects have finalize() methods, your app’s memory usage and GC time will increase significantly.


3️⃣ It Can Lead to Memory Leaks

If the finalizer itself references other objects, those objects can’t be collected immediately — keeping them alive longer than necessary.

That means finalize() can delay or prevent memory cleanup entirely.


4️⃣ It Can Be Dangerous

You can resurrect objects inside finalize() (by assigning this to a static variable), which causes bizarre and unpredictable behavior.

Example:

class Demo {
    static Demo instance;

    @Override
    protected void finalize() {
        instance = this; // The object comes back to life!
        System.out.println("Resurrected!");
    }
}
Enter fullscreen mode Exit fullscreen mode

This kind of code leads to hard-to-detect bugs and inconsistent program states.


🧠 What Should You Use Instead?
✅ Use try-with-resources

When dealing with files, sockets, or streams, always use try-with-resources.
It’s safer, faster, and guaranteed to close resources properly.

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class Main {
    public static void main(String[] args) {
        try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))) {
            System.out.println(br.readLine());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

The BufferedReader is automatically closed — no need for finalize().


✅ Use Cleaner API (Java 9+)

Java 9 introduced the java.lang.ref.Cleaner — a safe replacement for finalize().

It provides controlled cleanup without the unpredictability of finalizers.

Example:

import java.lang.ref.Cleaner;

class Resource {
    private static final Cleaner cleaner = Cleaner.create();

    static class State implements Runnable {
        @Override
        public void run() {
            System.out.println("Cleaning resource safely...");
        }
    }

    private final Cleaner.Cleanable cleanable;

    Resource() {
        this.cleanable = cleaner.register(this, new State());
    }
}

public class Main {
    public static void main(String[] args) {
        new Resource();
        System.gc();
    }
}
Enter fullscreen mode Exit fullscreen mode

✅ The Cleaner runs cleanup tasks safely and efficiently, without blocking GC.


🧾 What the Official Docs Say

Oracle officially marked finalize() as deprecated in Java 9 and removed it from recommendation entirely.

📘 Official Documentation — Why Finalizers Are Deprecated


🧭 Best Practices

💡 Never override finalize() in new code.
💡 Use try-with-resources for automatic cleanup.
💡 Use Cleaner API for advanced or background resource management.
💡 Profile and monitor resource usage instead of relying on GC behavior.


⚰️ Summary — Finalize Is a Relic

finalize() was once thought to be helpful, but it’s now:

❌ Unpredictable
❌ Performance-heavy
❌ Potentially dangerous

Modern Java gives you much better tools for safe cleanup.
So, if you ever see finalize(), just remember: let it rest in peace. 🪦


💬 Questions for you:

Have you ever used finalize() in an older Java project?

Did it ever cause unpredictable behavior or performance issues?

Have you switched to the Cleaner API or try-with-resources yet?


Would you like me to do tomorrow’s post about the Cleaner API itself — showing how it actually works internally and why it’s the modern replacement for finalize()?

Top comments (0)