Java disallows usage of final variable inside a supplier as it might not be initialized, yet prepending "(this)." to variable makes it compile and run fine.
Furthermore calling such supplier results in NullPointerException instead of compiler error if called before assigning the variable and runs as expected if called after.
Is this behaviour described somewhere?
I am using OpenJDK 1.8.0_151.
Example:
import java.util.function.Supplier;
class Example {
final String str;
Supplier<Integer> test1 = () -> str.length(); // DOES NOT COMPILE
Supplier<Integer> test2 = () -> this.str.length(); // DOES NOT COMPILE
Supplier<Integer> test3 = () -> (this.str).length(); // DOES NOT COMPILE
Supplier<Integer> test4 = () -> (this).str.length(); // OK
Example(String str) {
System.out.println(test4.get()); // NullPointerException
this.str = str;
System.out.println(test4.get()); // OK
}
}
---
javac Example.java
Example.java:7: error: variable str might not have been initialized
Supplier<Integer> test1 = () -> str.length(); // DOES NOT COMPILE
^
Example.java:8: error: variable str might not have been initialized
Supplier<Integer> test2 = () -> this.str.length(); // DOES NOT COMPILE
^
Example.java:9: error: variable str might not have been initialized
Supplier<Integer> test3 = () -> (this.str).length(); // DOES NOT COMPILE
^
3 errors
From JLS version 9, chapter 16:
Each local variable (§14.4) and every blank final field (§4.12.4, §8.3.1.2) must have a definitely assigned value when any access of its value occurs.
An access to its value consists of the simple name of the variable (or, for a field, the simple name of the field qualified by this) occurring anywhere in an expression except as the left-hand operand of the simple assignment operator = (§15.26.1).
str
is the simple name of a final field, and this.str
is the simple name of the field qualified by this
. (this).str
doesn't fall under either of those cases ((this)
doesn't count as "qualified by this
"), so it doesn't count as an access.