The final Keyword in Java
final means cannot be reassigned, cannot be overridden or cannot be extended, depending on where it is written.
-
Java Basics
- Introduction to Java
- Setting Up Java and Writing Your First Program
- Variables, Data Types and Literals in Java
- Type Casting and Type Conversion in Java
- Operators and Expressions in Java
- Input and Output in Java
- Comments, Keywords and Naming Conventions in Java
- Control Flow in Java: if, else and switch
- Loops in Java: for, while and do-while
- Methods
- Arrays and Strings
-
OOP
- Classes and Objects in Java
- Constructors in Java
- The this Keyword in Java
- The static Keyword in Java
- Encapsulation in Java
- Access Modifiers in Java
- Inheritance in Java
- Method Overriding and super in Java
- Polymorphism in Java
- Abstraction, Abstract Classes and Interfaces in Java
- Composition, Aggregation and Association in Java
- The Object Lifecycle in Java
- Core Java
- Exception Handling
-
Collections
- The Java Collections Framework
- List in Java: ArrayList, LinkedList, Vector and Stack
- Set in Java: HashSet, LinkedHashSet and TreeSet
- Map in Java: HashMap, LinkedHashMap and TreeMap
- How HashMap Works Internally in Java
- Queue and Deque in Java: ArrayDeque and PriorityQueue
- Iterators in Java
- Comparable and Comparator in Java
- Collections Utilities and Choosing the Right Collection
- Generics
- Java 8+
- Stream API
- Date and Time
- File and I/O
-
Multithreading
- Threads in Java: Processes, Runnable and Thread
- Thread Lifecycle in Java
- Synchronization in Java: synchronized and volatile
- Locks and Atomic Classes in Java
- Race Conditions and Deadlocks in Java
- The Executor Framework and Thread Pools in Java
- Future and CompletableFuture in Java
- Concurrent Collections in Java
- The Java Memory Model
- JVM and Memory
- Advanced Java
- Networking
- JDBC
- Testing
Three meanings, one keyword
| Applied to | Meaning |
|---|---|
| Variable | May be assigned once; cannot be reassigned |
| Method | Cannot be overridden by a subclass |
| Class | Cannot be extended |
final variables
final int maxRetries = 3;
// maxRetries = 5; // compile error
final List<String> names = new ArrayList<>();
names.add("Meera"); // allowed - the list is mutable
// names = new ArrayList<>(); // compile error - the reference is fixedThis is the single most misunderstood point.finalfreezes the variable, never the object it refers to. For an immutable object use a type such asString,List.of(...)or a record.
final fields
public class Invoice {
private final String reference; // assigned in the constructor
private final LocalDate issued = LocalDate.now(); // assigned inline
private static final double TAX = 0.18; // a constant
public Invoice(String reference) {
this.reference = reference; // must be assigned exactly once
}
}A final instance field must be assigned exactly once, either inline, in an instance initialiser, or in every constructor. A static final field must be assigned inline or in a static block.
final parameters and effectively final
public void process(final String input) {
// input = input.trim(); // compile error
}
public Runnable makeTask() {
int count = 5; // not declared final, but never reassigned
return () -> System.out.println(count); // allowed: effectively final
}Since Java 8 a lambda or an anonymous class may capture a local variable that is effectively final, meaning it is never reassigned after initialisation. Adding count++ anywhere would break the capture and produce a compile error.
final methods
public class Account {
public final void audit() { // subclasses cannot change this
record();
notifyCompliance();
}
protected void record() { } // subclasses may customise this part
protected void notifyCompliance() { }
}Marking a method final states that its behaviour is part of the guarantee of the class. It is the right tool when overriding would break an invariant, and it is commonly used for the outer method of a template method pattern.
final classes
public final class Money { } // cannot be extendedString, Integer and the other wrappers are final. For String that is essential: if it could be subclassed, a malicious subclass could change behaviour after a security check had passed.
final and immutability
public final class Period {
private final LocalDate start;
private final List<String> tags;
public Period(LocalDate start, List<String> tags) {
this.start = start;
this.tags = List.copyOf(tags); // defensive copy, immutable result
}
public List<String> tags() {
return tags; // safe to return, it cannot change
}
}An immutable class needs four things: the class is final, all fields are private final, no method changes state, and mutable inputs and outputs are copied. final alone gives you only the third of the way there.
final and the memory model
final fields carry a threading guarantee: once a constructor completes without leaking this, every thread that sees the object sees its fully initialised final fields. That guarantee does not extend to non final fields, which is one more reason to prefer immutable objects in concurrent code.
Common mistakes
- Believing
finalmakes a collection unmodifiable. - Forgetting to assign a
finalfield in one of several constructors. - Reassigning a captured local variable and then not understanding the lambda compile error.
- Declaring
static finalon a mutable object and treating it as a constant. - Making everything
finalmechanically, including parameters, which adds noise without value.
Best practices
- Make fields
finalby default and relax only when mutation is genuinely required. - Use
static finalwith truly immutable values such asList.of(...). - Make value classes
finalsoequalscannot be undermined by a subclass. - Use
finalmethods to protect invariants rather than as a general habit. - Skip
finalon parameters unless the team has agreed on it.
Practice
- Explain why
final List<String> l = new ArrayList<>(); l.add("x");compiles. - Write a class with two constructors where one forgets a
finalfield, and read the error. - Why does a lambda refuse to capture a variable that is incremented later?
- Make a class genuinely immutable and list every change required.
- Why is
Stringdeclaredfinal, in terms of security?
Conclusion
On a variable final stops reassignment, on a method it stops overriding, on a class it stops extension. It is a building block of immutability, not immutability by itself.