I have an anonymous inner class and an equivalent lambda. Why are the variable initialization rules stricter for the lambda, and is there a solution cleaner than an anonymous inner class or initializing it in the constructor?
import java.util.concurrent.Callable;
public class Immutable {
private final int val;
public Immutable(int val) { this.val = val; }
// Works fine
private final Callable<String> anonInnerGetValString = new Callable<String>() {
@Override
public String call() throws Exception {
return String.valueOf(val);
}
};
// Doesn't compile; "Variable 'val' might not have been initialized"
private final Callable<String> lambdaGetValString = () -> String.valueOf(val);
}
Edit: I did run across one workaround: using a getter for val
.
This won't compile:
but this will:
and so will this:
So it's nothing to do with lambdas. A field that is initialized on the same line that it is declared on is evaluated before the constructor is executed. So at that point, the variable 'val' (or in this example 'x') has not been initialized.
The chapter on lambda expression bodies states
They're more strict because of that.
The surrounding context, in this case, is an assignment to a field and the issue at hand is an access of a field,
val
, a blankfinal
field, in the right hand side of the expression.The Java Language Specification states
It then goes on to say
Your code basically looks like this
The compiler therefore determines that
val
in unassigned when it's access within the initialization expression forlambdaGetValString
.The rules above apply to the use of a simple name,
val
, not to a qualified expression,this.val
. You can use