Feu*_*mel 21 lambda javac java-8
以下类包含一个成员变量runnable,该变量使用匿名内部类的实例进行初始化.内部类引用相同的成员:
class Example {
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println(runnable);
}
};
}
Run Code Online (Sandbox Code Playgroud)
只要在分配成员之前未执行该方法并且JLS允许这样的引用,这就不是问题.
理论上,成员变量的声明可以转换为lambda表达式,如下所示:
Runnable runnable = () -> System.out.println(runnable);
Run Code Online (Sandbox Code Playgroud)
根据我的理解,这在功能上等同于前面的示例,但它被javac 1.8.0_05以下错误消息拒绝:
Error:(2, 54) java: self-reference in initializer
Run Code Online (Sandbox Code Playgroud)
虽然这种说法是正确的,但我不明白为什么不允许这样做.这是故意不允许的,可能是因为lambda表达式被编译为不同的字节代码,如果它被允许会导致问题?或者刚被禁止,因为这些引用在匿名内部类中使用时已经存在问题?还是JLS作家无意中不允许这样做?或者它是一个错误javac?
小智 28
Bug#JDK-8027941正是如此描述的.丹·史密斯(项目Lambda规范主管)写道,这不是一个错误,不仅限于lambdas.
在对相关错误报告的评论中,他这样说:
8.3.2.3:首先,如果在现场声明之前使用,则通常禁止在字段初始化程序中"使用"字段.规范对此并不十分清楚,但意图一直是"之前"包括字段自己的初始化程序.所以"
int x = x+1;"不是有效的字段声明.
他还说:
可以添加一个特殊处理lambda体的特性,比如匿名类的体(或者更常见的是,如果它是一个变量初始化器,允许lambda引用它自己),但是这还没有完成.(FWIW,8.3.2.3的直接调整并不完全安全,就像第4个子弹目前还不完全安全一样:"
Function f = (Function) ((Function) e -> f.apply(e)).apply(null);".)
我认为问题在于Java的设计者希望有简单的语法规则来决定允许哪种语句,而不是依赖于更复杂的语义代码分析.好处可能是一个更简单的规范,因此编译器的要求更少,而成本是程序员无法表达每个程序 - 至少不是他们想要的方式.
正如Marko Topolnik指出的那样,有一个解决方案:完全符合该领域的资格.错误报告中的示例:
import java.util.function.Function;
public class LambdaSelfRef {
// COMPILATION FAILURE
public static Function<Object, Object> op1 = e -> op1.apply(e);
// COMPILES OK
public static Function<Object, Object> op2 = e -> LambdaSelfRef.op2.apply(e);
/* ... */
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2600 次 |
| 最近记录: |