Effectively final local variable cannot be declared as final

Tagir Valeev amaembo at gmail.com
Tue Sep 27 10:03:32 UTC 2022


Hello!

Consider the following code:

public class Demo {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            Runnable r = () -> System.out.println(i);
            r.run();
            break;
        }
    }
}

It can be compiled with javac (version 19), successfully executed and
prints 0. As only effectively final locals are allowed to be captured
in lambda, I conclude that `i` is effectively final. I also assumed
that for every effectively final variable, it's possible to write an
explicit `final` modifier. However, this is not the case. The
following code fails with the compilation error:

public class Demo {
    public static void main(String[] args) {
        for (final int i = 0; i < 10; i++) {
            Runnable r = () -> System.out.println(i);
            r.run();
            break;
        }
    }
}
Demo.java:3: error: cannot assign a value to final variable i
        for (final int i = 0; i < 10; i++) {
                                      ^
1 error
error: compilation failed

In my opinion, either both should be accepted or both should be
rejected. According to JLS 4.12.4, I'm inclined that both should be
rejected:

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).

Here, `i` has an initializer and also occurs as the operand of prefix
increment, so it cannot be effectively final.

What do you think?

With best regards,
Tagir Valeev.


More information about the compiler-dev mailing list