It has nothing to do with the lambda, this example has the same error:
public class Test {
private final String a;
private String b = a; // // Variable 'a' might not have been initialized
public Test(String a) {
this.a = a;
}
}
It's because the initialization at the place of declaration is executed before the constructor. Therefore, at the place of the declaration of b
, a
is still not initialized.
It's clear when you use this example:
public class Test {
private String a = "init";
private String b = a;
public Test(String a) {
this.a = a;
}
public static void main(String[] args) {
System.out.println(new Test("constructor").b);
}
}
When you run it, it prints "init"
(the value to which field a
was originally assigned) and not "constructor"
because the initialization of b
took place before running the constructor.
The lambda from your example makes the it a bit more convoluted, because we could expect that since the access to a
is deferred, it would be OK with the compiler, but apparently the compiler just follows the general rule of "don't access the variable before it's initialized".
You can bypass it using an accessor method:
public class Test {
private final String a;
private String b = getA(); // allowed now, but not very useful
private Function<String, String> f = e -> getA(); // allowed now and evaluated at the time of execution of the function
public Test(String a) {
this.a = a;
}
public static void main(String[] args) {
System.out.println(new Test("constructor").b); // prints "null"
System.out.println(new Test("constructor").f.apply("")); // prints "constructor"
}
public String getA() {
return a;
}
}