Final Variables in Java
A final variable can be assigned exactly once. The variable is fixed; the object it refers to may still be mutable. Use final on fields to make immutable classes; on locals and parameters to document intent and prevent accidental reassignment.
Final locals
final int max = computeMax();
max = 200; // β compile error
for (final String s : items) { process(s); } // loop variable is fresh each iteration β legal
Final parameters
public void handle(final Event e) {
e = new Event(); // β cannot reassign
e.process(); // β
using the object is fine
}
Final fields
public class Order {
private final long id;
private final List<Item> items;
public Order(long id, List<Item> items) {
this.id = id;
this.items = List.copyOf(items); // immutable snapshot
}
}
Every field that doesn't need to change should be final. Classes built from final fields are safely shared across threads after construction.
Static final β constants
public static final int MAX_RETRY = 3;
public static final String BASE_URL = "https://api.example.com";
final β immutable
final List<String> names = new ArrayList<>();
names.add("Alice"); // β
the list is mutable
names = new ArrayList<>(); // β but the variable is final
For true immutability: use List.copyOf, Collections.unmodifiableList, or records.
Effectively final β for lambdas and inner classes
int counter = 0;
list.forEach(s -> counter++); // β counter must be final or effectively final
// Workaround β use an accumulator
var sum = list.stream().mapToInt(String::length).sum();
// Or an AtomicInteger if you really need mutable shared state
var count = new AtomicInteger(0);
list.forEach(s -> count.incrementAndGet());
Style: mandatory final?
Some teams require final on every parameter and local that can be. It prevents accidental reassignment and makes intent explicit, but adds visual noise. Pick a convention and stick to it β IDE auto-insertion takes the tedium out.
Common mistakes
- Treating
finalas immutable β wrap mutable collections withList.copyOf. - Skipping
finalon fields by default β most fields shouldn't mutate. Make immutability the default. - Trying to mutate captured locals β they must be effectively final. Use an accumulator or an array of length 1.
Related
Pillar: Variables in Java. See also final keyword, records.