Final, Finally, and Finalize in Java Explained with Real-World Scenarios and Complex Example

Deep explanation of final, finally, and finalize in Java with real-world scenarios, production use cases, and a combined complex example.

Final, Finally, and Finalize in Java (Deep Dive)

In Java, final, finally, and finalize are completely different concepts but often confused due to similar naming. Understanding them is critical for interviews and backend system design.

1. final Keyword (Immutability & Restriction)

The final keyword is used to restrict modification in Java. It can be applied to variables, methods, and classes.

  • final variable → value cannot be changed
  • final method → cannot be overridden
  • final class → cannot be inherited

Real-World Use Cases

  • Bank interest rate constant (final variable)
  • Security logic method that should not be overridden
  • Utility classes like Math or String in Java (final class)
final double INTEREST_RATE = 7.5;
// INTEREST_RATE = 8.0; ❌ not allowed

2. finally Block (Guaranteed Execution)

finally is used in exception handling. It always executes whether an exception occurs or not.

Real-World Use Cases

  • Closing database connections
  • Releasing file handles
  • Logging audit trails after API execution
  • Cleaning up network resources
try {
    int result = 10 / 0;
} catch (Exception e) {
    System.out.println("Exception handled");
} finally {
    System.out.println("Cleanup: closing resources");
}

3. finalize() Method (Garbage Collection - Deprecated)

finalize() is called by Garbage Collector before destroying an object. It was used for cleanup but is now deprecated due to unpredictability.

Real-World Use Cases (Legacy Systems Only)

  • Old file cleanup logic
  • Legacy memory tracking systems
  • Debugging object destruction (not recommended in production)
class Demo {
    @Override
    protected void finalize() throws Throwable {
        System.out.println("Object destroyed by GC");
    }
}

🔥 Complex Combined Example (All Concepts Together)

This example simulates a banking system where all three concepts are used together.

class BankAccount {

    // final variable (constant interest rate)
    final double INTEREST_RATE = 6.5;

    BankAccount() {
        System.out.println("Account created");
    }

    // finally example inside method
    void processTransaction() {
        try {
            System.out.println("Processing transaction...");
            int x = 10 / 0; // exception
        } catch (Exception e) {
            System.out.println("Transaction failed");
        } finally {
            System.out.println("Transaction log saved (finally block)");
        }
    }

    // finalize (deprecated concept)
    @Override
    protected void finalize() throws Throwable {
        System.out.println("Cleaning up account object before GC");
    }
}

public class Main {
    public static void main(String[] args) {
        BankAccount account = new BankAccount();
        account.processTransaction();

        account = null;
        System.gc(); // Suggest GC call
    }
}

Real Output Scenario Flow

  • Account created
  • Processing transaction...
  • Transaction failed
  • Transaction log saved (finally block)
  • Cleaning up account object before GC (may or may not run)

Final Summary

  • final → ensures immutability and safety
  • finally → ensures cleanup always happens
  • finalize → GC cleanup (deprecated and unreliable)
  • Used together in enterprise systems for safety, cleanup, and lifecycle control

Real-World System Design Perspective

In real banking or e-commerce systems, final is used for constants like tax rates, finally ensures database connections are always closed, and finalize is avoided in modern systems in favor of try-with-resources and explicit cleanup.

Modern Java applications prefer deterministic resource management instead of relying on finalize().