java 为什么有匿名类,为什么Java 8中的lambdas不允许对匿名类没有的成员变量进行前向引用?...

The following class contains a member variable runnable which is initialized with an instance of an anonymous inner class. The inner class references the same member:

class Example {

Runnable runnable = new Runnable() {

@Override

public void run() {

System.out.println(runnable);

}

};

}

This is not a problem as long as the method is not executed before the member has been assigned and the JLS allows such a reference.

The declaration of the member variable could theoretically be converted to a lambda expression like this:

Runnable runnable = () -> System.out.println(runnable);

To my understanding, this is functionally equivalent to the previous example, but it is rejected by javac 1.8.0_05 with the following error message:

Error:(2, 54) java: self-reference in initializer

While that statement is true, I do not see why this was disallowed. Was this intentionally disallowed, maybe because lambda expressions are compiled to different byte code which would lead to problems if it was allows? Or was just disallowed because there were already problems with these references when they were used in anonymous inner classes? Or was it unintentionally disallowed by the JLS writers? Or is it a bug in javac?

解决方案

Bug #JDK-8027941 describes exactly this. Dan Smith (Project Lambda Specification Lead) writes that it's not a bug, and not limited to lambdas.

In the comments on a related bug report, he puts it like this:

8.3.2.3: First, a "use" of a field in a field initializer is generally prohibited if the use occurs before the field declaration. The spec is not very clear on this, but the intent has always been that "before" includes the field's own initializer. So "int x = x+1;" is not a valid field declaration.

He also remarks:

It would possible to add a feature that would treat lambda bodies specially, like bodies of anonymous classes (or, more generally, allow a lambda to refer to itself if it is a variable initializer), but this has not been done. (FWIW, a straightforward tweak of 8.3.2.3 would not be entirely safe, just like the 4th bullet is not currently entirely safe: "Function f = (Function) ((Function) e -> f.apply(e)).apply(null);".)

I think the problem is that the designers of Java want to have simple, syntactic rules to decide what kind of statements are allowed, rather than depending on more complex, semantic code analysis. The benefit is probably a simpler spec and therefore less requirements on compilers, while the cost is that programmers can't express every program -- at least not in the way they want to.

As Marko Topolnik points out, there is a solution: fully qualify the field. Example from the bug report:

import java.util.function.Function;

public class LambdaSelfRef {

// COMPILATION FAILURE

public static Function op1 = e -> op1.apply(e);

// COMPILES OK

public static Function op2 = e -> LambdaSelfRef.op2.apply(e);

/* ... */

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值