What is the difference between final, finally and finalize in Java?
final is a keyword that stops change (a variable cannot be reassigned, a method cannot be overridden, a class cannot be extended). finally is a block that runs after try/catch, usually for cleanup. finalize() was a method the garbage collector might call before removing an object; it is deprecated for removal and should not be used.
Explain it simply
The three words sound alike but do completely unrelated jobs.
- final is a "do not change" stamp. Like your date of birth on an Aadhaar card: once set, it stays.
- finally is the "always do this before leaving" step. Like switching off the lights when you leave the classroom, whether the lecture went well or the fire alarm rang.
- finalize was a goodbye note the garbage collector might read before throwing an object away. Nobody could say when, or even whether, it would be read, so Java has deprecated it.
Example
public class ThreeFs {
static final double GST_RATE = 0.18; // final variable: a constant
static int divide(int a, int b) {
try {
return a / b;
} catch (ArithmeticException e) {
System.out.println("Cannot divide by zero");
return 0;
} finally {
System.out.println("Done dividing"); // runs in both cases
}
}
public static void main(String[] args) {
System.out.println(divide(10, 2));
// prints: Done dividing
// prints: 5
System.out.println(divide(10, 0));
// prints: Cannot divide by zero
// prints: Done dividing
// prints: 0
}
}How it works
final can be applied in three places:
- On a variable: it can be assigned only once. For an object reference, the reference cannot change, but the object's contents can (a
final Listcan still have items added). - On a method: subclasses cannot override it.
- On a class: no class can extend it.
StringandIntegerare final classes.
finally is attached to a try block. It runs whether the try finishes normally, an exception is caught, or an exception escapes, and even when the try block has a return. It does not run if the JVM stops, for example with System.exit() or a crash.
finalize() is a method on Object that the garbage collector could call before reclaiming an object. It was deprecated in Java 9 and marked deprecated for removal in Java 18 (JEP 421). It was unreliable: there was no guarantee of when it runs or that it runs at all, it slowed down garbage collection, and errors inside it were silently ignored.
Real-world use
finalfor constants such as tax rates, for fields in immutable classes, and for classes you do not want extended.finallyfor releasing locks (lock.unlock()in a finally block) and other cleanup. For files, sockets and database connections, try-with-resources is cleaner, because it closes them automatically.- Instead of
finalize(), use try-with-resources withAutoCloseable, orjava.lang.ref.Cleaneras a safety net.
Common mistakes
- Thinking a
finalobject is immutable. Only the reference is fixed. - Putting
returninsidefinally. It overrides the try's return value and silently swallows any exception. - Saying finalize "is called when an object is destroyed" as if it were a reliable destructor. Java has no destructors.
What to say in the interview
"They're unrelated despite the names. final is a keyword: a final variable can be assigned once, a final method can't be overridden, and a final class can't be extended. finally is a block after try or catch that always runs for cleanup, unless the JVM itself exits. finalize was an Object method the garbage collector might call before reclaiming an object, but it was unreliable, so it's deprecated for removal since Java 18. For cleanup today I use try-with-resources or a Cleaner."
Follow-up questions
- Does finally run if there is a
returnin the try block? - Can a
finalvariable be assigned in a constructor? - Why is
Stringa final class? - What is try-with-resources?
Go deeper
Read these once the basics above feel easy.
A final field that is not given a value where it is declared is called a blank final, and every constructor must assign it exactly once. Final fields also have a useful guarantee in the Java Memory Model: once a constructor finishes, other threads that see the object are guaranteed to see the correctly initialised values of its final fields, which is one reason immutable objects are safe to share between threads. Local variables used inside lambdas or anonymous classes must be final or "effectively final", meaning they are never reassigned after initialisation.