我不明白这种行为。
这段代码符合:
public class A {
private final String s;
private Function<String, String> f = e -> s; // Variable 's' might not have been initialized
public A(String s) {
this.s = s;
}
}
但如果我使final
成为最终版,那么我会收到编译错误:
final
为什么?如果是另一种方式,我明白了,但是当我声明一个字段[assembly: log4net.Config.XmlConfigurator(Watch = true)]
(这迫使我在构造函数中初始化它的值)时,编译器是怎么抱怨的,当它是的时候就可以了。不是::-webkit-scrollbar {
width: 50px;
height: 18px;
&-track {
border: 0px;
border-radius: 0px;
background-color: transparent !important;
}
&-thumb {
background-color: rgba(213, 213, 213, 0.4) !important;
border: 0px;
border-radius: 0px;
}
}
// for new opened files
.vertical-scrollbar {
width: 50px !important;
}
?
答案 0 :(得分:12)
它与lambda无关,这个例子有同样的错误:
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;
}
}
这是因为声明位置的初始化是在构造函数之前执行的。因此,在声明b
的地方,a
仍未初始化。
使用此示例时很清楚:
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);
}
}
当您运行它时,会打印"init"
(最初分配字段a
的值)而不是"constructor"
,因为b
的初始化发生了在运行构造函数之前。
你的例子中的lambda使它更复杂,因为我们可以预期,由于对a
的访问被推迟,编译器就可以了,但显然编译器只遵循一般规则“在初始化之前不要访问变量”。
您可以使用访问者方法绕过它:
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;
}
}
答案 1 :(得分:5)
非最终成员变量将始终被初始化(因为它具有默认值 - null
变量的情况下为String
,因此不可能未初始化它。
另一方面,最终变量只能初始化一次,所以我假设它没有初始化为默认值。
我发现最接近的相关内容是JLS 4.12.4.:
4.12.4。最终变量
变量可以声明为final。最终变量只能分配一次。如果指定了最终变量,则为编译时错误,除非在分配之前明确未分配
我假设我们可以理解最后一句话意味着最终变量没有被赋予默认值,否则你将在this.s = s;
得到编译时错误。
更好的JLS参考(感谢Holger)是JLS 16:
第16章。明确分配
对于本地变量或空白最终字段x的每次访问,必须在访问之前明确分配x,否则发生编译时错误。
这个要求背后的理性是(在你的例子中)lambda表达式可以在初始化s
之前调用:
public A(String s) {
String v = f.apply("x"); // this.s is not initialized at this point
// so it can't be accessed
this.s = s;
}
请注意,在初始化最终变量之后,您可以在构造函数中初始化lambda表达式(我将参数的名称更改为与成员变量不同,以便lambda表达式不会获取该局部变量): / p>
public A(String so) {
// f = e -> s; // Error: The blank final field s may not have been initialized
this.s = so;
f = e -> s; // works fine
}
答案 2 :(得分:0)
这也是可行的方法
public class A {
private final String s;
private Function<String, String> f;
public A(String s) {
this.s = s;
this.f = e -> s;
}
}