The final Keyword in Java
The final keyword in Java means "this can't change". You can use it on variables
(assign once), methods (no overriding), and classes (no subclassing). It makes code safer and easier to reason
about, but there's one big misunderstanding about final that trips up nearly every beginner.
What does final mean in Java?
Think of writing in pen instead of pencil. Once something is written in pen, it stays. final is
Java's pen, and you can apply it in five places:
Where can you use final?
final variable
Can be assigned only once. Trying to reassign it is a compile error.
final int maxPlayers = 4;
maxPlayers = 5; // ✘ cannot assign a value to final variable final field
Set once, in the declaration or in every constructor, then fixed for the object's whole life.
private final String id;
User(String id) {
this.id = id; // must happen exactly once
} static final
A class-wide constant. Named in UPPER_SNAKE_CASE by convention.
public static final int MAX_LOGIN_ATTEMPTS = 3; final method
Inherited by subclasses but can't be overridden. Protects logic that must not change.
public final boolean checkPassword(String input) {
// subclasses can't replace this
} final class
Can't be extended at all. String, Integer, and LocalDate are final.
public final class Money { }
class FakeMoney extends Money { } // ✘ cannot inherit from final Money Final variables: assign once
final double taxRate = 0.18;
taxRate = 0.20; // ✘ compile error: cannot assign a value to final variable taxRate A final variable doesn't need a value right away. It just needs exactly one assignment before it's used:
final String greeting;
if (hour < 12) {
greeting = "Good morning";
} else {
greeting = "Good afternoon";
}
// greeting is now fixed Why bother making a variable final?
It tells the reader "this never changes, so you don't need to track it". It also stops accidental
reassignment bugs. Many teams make every field final unless it truly needs to change.
Final fields and immutable objects
A final field without a value is called a blank final. Java forces every constructor to set it exactly once:
public class User {
private final String id; // blank final
private final String email;
public User(String id, String email) {
this.id = id;
this.email = email;
}
public String getId() { return id; }
}
With only final fields and no setters, a User can never change after it's created. That's an
immutable object, which is safe to share anywhere, even between threads.
Shortcut: a record (Java 16+) gives you this for free. record User(String id, String email) { } makes final fields, a constructor, getters, equals, hashCode, and toString.
The big gotcha: final doesn't freeze the object
For object variables, final locks the reference (which object the variable points to),
not the object itself:
final List<String> cart = new ArrayList<>();
cart.add("Apples"); // ✔ allowed: changing the list's contents
cart.add("Bread");
System.out.println(cart);
cart = new ArrayList<>(); // ✘ compile error: can't point cart at a different list [Apples, Bread]
What final locks, and what it doesn't
| Action | Allowed with final List? |
|---|---|
| Add, remove, or change items | ✔ Yes. The list object isn't frozen. |
| Point the variable at another list | ✘ No. The reference is locked. |
It's like a parking spot reserved for one specific car. The car can't be swapped, but you can still put things in its boot.
If you need a list that can't change, use an unmodifiable list:
List<String> days = List.of("Mon", "Tue", "Wed");
days.add("Thu"); // ✘ throws UnsupportedOperationException at runtime Final methods: no overriding
A final method is inherited normally, but subclasses can't replace it. Use it for logic that must
behave the same way for every subclass, like a security check:
class Account {
public final boolean canWithdraw(double amount, double balance) {
return amount > 0 && amount <= balance;
}
}
class SneakyAccount extends Account {
@Override
public boolean canWithdraw(double amount, double balance) { // ✘ compile error: overridden method is final
return true;
}
} Final classes: no subclassing
A final class can't be extended. String is final, so nobody can create a
FakeString that breaks the guarantee that strings never change. To allow only some
subclasses, Java 17 added sealed classes. See inheritance in Java.
What is "effectively final"?
Lambdas and inner classes can only use local variables that never change after being assigned. You don't have to
write final; if you never reassign the variable, Java treats it as effectively final:
String prefix = "Item: "; // never reassigned → effectively final
List.of("pen", "cup").forEach(x -> System.out.println(prefix + x)); // ✔ works Item: pen Item: cup
final vs finally vs finalize
| Name | What it is | Use it? |
|---|---|---|
final | Keyword: prevents reassignment, overriding, or subclassing | ✔ Often |
finally | Block after try/catch that always runs, for cleanup | ✔ When needed (try-with-resources is often cleaner) |
finalize() | Old method the garbage collector might call before deleting an object | ✘ Deprecated for removal since Java 18 (JEP 421) |
Quick recap
- Final variable = assigned once. Final method = no overriding. Final class = no subclassing.
static finalcreates constants, likeMAX_LOGIN_ATTEMPTS.finallocks the reference, not the object; useList.of()for a list that can't change.- Lambdas can use local variables that are final or effectively final.
What's next?
You've seen new on almost every page. Find out exactly what it does in the
new keyword guide, or pair final with
static for constants.
Frequently Asked Questions
What does final mean in Java?
final means 'can't be changed after it's set'. A final variable can be assigned only once, a final method can't be overridden by a subclass, and a final class can't be extended at all.
Does final make an object immutable?
No. final only locks the reference, meaning which object the variable points to. The object itself can still change. A final List can have items added and removed; you just can't point the variable at a different list. For a list that can't change, use List.of(...) or List.copyOf(...).
What is a blank final variable?
A final field declared without a value, like 'private final String id;'. Java requires it to be assigned exactly once in every constructor. It's the standard way to make fields that are set when the object is created and never change afterwards.
What is the difference between final, finally and finalize?
final is a keyword that prevents changes. finally is a block after try/catch that always runs, used for cleanup. finalize() was an Object method the garbage collector could call before destroying an object; it's deprecated for removal since Java 18, so use try-with-resources instead.
Why is the String class final in Java?
So nobody can create a subclass that changes how strings behave. Java relies on strings being immutable for security (file paths, class names), for safe sharing between threads, and for caching. A final class guarantees that every String really behaves like a String.