Java: What is effectively final?

Prerequisit: What does final mean, and are final variables always immutable?

Effectively Final

A variable is effectively final if you could mark it as final without introducing compilation errors.

Relevance to inner classes and lambdas

Unlike for example JavaScript, inner classes and lambdas can't access mutable variables in the enclosing scope. Such variables must be final or effectively final.

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.

Formal definition

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 final.
    • 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 final.
    • 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

Comments

Be the first to comment!