Java: What is effectively final?
Prerequisit: What does final mean, and are final variables always immutable?
A variable is effectively final if you could mark it as
final without introducing compilation errors.
Relevance to inner classes and lambdas
int i = 0; // Effectively final i++; // No longer effectively final Runnable r = () -> System.out.println(i); Compile error
With the introduction of lambdas, closures became much more common. The notion of "effectively final" was introduced to alleviate the programmer from having to frequently mark variables as
final to satisfy the compiler.
Here's the formal definition from JLS §4.12.4:
Certain variables that are not declared final are instead considered effectively final:
- A local variable whose declarator has an initializer (§14.4.2) is effectively final if all of the following are true:
- It is not declared
- It never occurs as the left hand side in an assignment expression (§15.26). (Note that the local variable declarator containing the initializer is not an assignment expression.)
- It never occurs as the operand of a prefix or postfix increment or decrement operator (§15.14, §15.15).
A local variable whose declarator lacks an initializer is effectively final if all of the following are true:
- It is not declared
- Whenever it occurs as the left hand side in an assignment expression, it is definitely unassigned and not definitely assigned before the assignment; that is, it is definitely unassigned and not definitely assigned after the right hand side of the assignment expression (§16, Definite Assignment).
- It never occurs as the operand of a prefix or postfix increment or decrement operator.
A method, constructor, lambda, or exception parameter (§8.4.1, §8.8.1, §9.4, §15.27.1, §14.20) is treated, for the purpose of determining whether it is effectively final, as a local variable whose declarator has an initializer.
If a variable is effectively final, adding the final modifier to its declaration will not introduce any compile-time errors. Conversely, a local variable or parameter that is declared final in a valid program becomes effectively final if the final modifier is removed. JLS §4.12.4