final vs finally vs finalize in Java: Key Differences Explained

Illustration for final vs finally vs finalize in Java: Key Differences Explained
By Last updated:

Three look-alike terms—final, finally, and finalize—serve completely different purposes in Java. Confusing them can cause compiler errors, logic bugs, or poor resource management. This article breaks down each term, shows real code, and highlights interview-ready differences.


⚡ Quick Comparison Table

Feature final (Keyword) finally (Block) finalize() (Method)
Category Modifier keyword Exception-handling block java.lang.Object method
Applied To Variables, methods, classes try-catch-finally Any class (via override)
Main Purpose Prevent change (immutability, no override, no subclass) Ensure cleanup code always runs Custom cleanup before garbage collection
When Executes Compile-time rule At runtime, after try / catch When GC decides to reclaim object
Can It Fail to Run? N/A Runs unless JVM crashes Might never run if GC not triggered
Typical Use-Case Constants, secure APIs Close files, release locks Rare—legacy resource cleanup

1️⃣ The final Keyword

1.1 Final Variable (Constant)

final String NAME = "John";
// NAME = "Jim"; // ❌ compile-time error

1.2 Final Method (No Override)

class Base {
    final void greet() { System.out.println("Hello"); }
}
class Sub extends Base {
    // void greet() { } // ❌ cannot override final method
}

1.3 Final Class (No Subclassing)

public final class ImmutableUtility { }
class Child extends ImmutableUtility { } // ❌ compile-time error

When to use: Immutability (constants), security APIs, or preventing subclassing for design reasons.


2️⃣ The finally Block

Guarantees execution regardless of whether an exception is thrown.

try {
    int result = 300 / divisor;
} catch (ArithmeticException ex) {
    System.out.println("Divide by zero!");
} finally {
    System.out.println("Cleanup runs here.");
}

Best Practices

  • Close streams (try-with-resources preferred in Java 7+).
  • Release locks or database connections.
  • Avoid return statements inside finally (can swallow exceptions).

3️⃣ The finalize() Method

Called by the Garbage Collector once before object destruction.

@Override
protected void finalize() throws Throwable {
    System.out.println("finalize() called");
}

public static void main(String[] args) {
    new FinalizeDemo();
    System.gc(); // Hint to run GC
}

Why You Should Avoid It

  • Execution time is unpredictable.
  • Adds GC overhead.
  • Deprecated for removal (JEP 421, Java 18).

Modern Alternative: Use try-with-resources or Cleaner API for explicit cleanup.


🚦 When to Use What

Scenario Use
Create immutable constant final variable
Prevent method override final method
Guarantee resource release finally block (or TWR)
Legacy cleanup before GC finalize() (discouraged)

🧠 Interview Nuggets

  1. Q: Can finally execute if System.exit(0) is called in try?
    A: No, JVM exits before finally runs.

  2. Q: Is finalize() guaranteed to run?
    A: No, JVM may terminate without calling it.

  3. Q: Can a final object’s internal state change?
    A: Yes—final prevents reassigning the reference, not object mutation.


🧭 Java Version Notes

Feature Status / Version Notes
final keyword Since Java 1.0 Core language feature
finally block Since Java 1.0 Core language feature
finalize() Deprecated since Java 9, forRemoval=true since Java 18 Use Cleaner or TWR instead

📝 Summary

  • final → immutability or inheritance control (compile-time).
  • finally → guaranteed cleanup after try / catch (runtime).
  • finalize() → legacy GC callback, avoid in modern code.

Takeaway: Prefer final for design clarity, finally (or better, try-with-resources) for cleanup, and avoid finalize() in new code.