我正在使用 Java 8 Update 20 32 位、Maven 3.2.3、Eclipse Luna Build id:20140612-0600 32 位。
开始使用 lambda 后,我的项目中的一些类开始在 Maven 中报告编译错误(mvn compile
).
仅当我使用 lambda 时才会出现这些错误。如果我切换回匿名类,错误就会消失。
我可以通过一个简单的测试用例重现该错误:
package br;
import java.awt.Button;
import java.awt.Panel;
public class Test {
private final Button button;
private final Panel panel;
public Test() {
button = new Button();
button.addActionListener(event -> {
System.out.println(panel);
});
panel = new Panel();
}
}
我这样编译:
mvn clean;mvn compile
我收到此错误:
[ERROR] /C:/Users/fabiano/workspace-luna/Test/src/main/java/br/Test.java:[14,44] variable panel might not have been initialized
尽管错误消息非常清楚地说明了正在发生的事情(编译器认为最终变量panel
在实例化之前被调用),直到按钮生成一个操作时才会调用该变量,并且我们不能说该操作何时发生,代码应该编译。事实上,如果我不使用 lambda,它会按应有的方式编译:
package br;
import java.awt.Button;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Test {
private final Button button;
private final Panel panel;
public Test() {
button = new Button();
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println(panel);
}
});
panel = new Panel();
}
}
我注意到与这个问题相关的另外两个奇怪的事情:
- Eclipse 在自动编译该类时不会报告此错误。 Eclipse 使用与 maven 相同的 JDK 来编译该类。
- 如果我使用maven使用匿名类来编译该类,然后我将该类更改为使用lambda并再次使用maven进行编译,它不会报告错误。在这种情况下,如果我使用它只会再次报告错误
mvn clean
其次是mvn compile
.
有人可以帮我解决这个问题吗?或者尝试重现这个问题?
尽管错误消息非常清楚地说明了发生的情况(编译器认为最终变量“panel”在实例化之前被调用),但直到按钮生成操作时才会调用该变量,我们不能说当操作发生时,代码应该编译。
您应该考虑这样一个事实:编译器遵循正式规则并且不了解您的知识。特别是,编译器无法知道该方法addActionListener
不调用actionPerformed
立即方法。它也不知道按钮的可见性决定了何时actionPerformed
可能会被称为。
正式行为有规格 http://docs.oracle.com/javase/specs/jls/se8/html/index.html。在那里你会发现以下几点:
第 16 章 明确分配 http://docs.oracle.com/javase/specs/jls/se8/html/jls-16.html
每个局部变量(第 14.4 节)和每个空白final
字段(§4.12.4,§8.3.1.2)必须有一个明确指定当对其值进行任何访问时的值。
对其值的访问由变量的简单名称组成(或者,对于字段,由以下条件限定的字段的简单名称)this
) 出现在表达式中的任何位置,但作为简单赋值运算符的左侧操作数除外=
(第 15.26.1 节)。
and
15.27.2。拉姆达身体 http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.27
…
与匿名类声明中出现的代码不同,名称的含义和this
and super
出现在 lambda 主体中的关键字以及引用声明的可访问性与周围上下文中的相同(除了 lambda 参数引入了新名称)。
在您的代码中,lambda 体内名称的含义是panel
,与周围上下文中的构造函数相同。在这种情况下,“每个空白final
字段必须有一个明确指定当发生对其值的任何访问时的值”适用。
是的,这与内部类定义不同。该规范明确指出。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)