为什么Java 8中的lambda不允许对匿名类不允许的成员变量进行前向引用?

火大理石

下列类包含一个成员变量runnable该成员变量使用匿名内部类的实例进行初始化。内部类引用相同的成员:

class Example {
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            System.out.println(runnable);
        }
    };
}

只要在分配成员之前不执行该方法,并且JLS允许这种引用,就不会有问题。

理论上,成员变量的声明可以转换为lambda表达式,如下所示:

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

据我了解,这在功能上与前面的示例等效,但是被javac 1.8.0_05以下错误消息拒绝

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

虽然这一说法是正确的,但我不明白为什么这是不允许的。是否故意禁止这样做,也许是因为lambda表达式被编译为不同的字节码,如果允许的话会导致问题吗?还是因为在匿名内部类中使用这些引用时已经存在问题而被禁止使用?还是JLS作家无意中禁止了它?还是其中的错误javac

用户名

错误#JDK-8027941对此进行了精确描述。项目Lambda规范负责人Dan Smith写道,这不是错误,并且不仅限于lambda。

有关错误报告的评论中,他这样说:

8.3.2.3:首先,通常禁止在字段初始化程序中使用字段,如果该使用发生在字段声明之前。规范对此并不十分清楚,但是一直的意图是“之前”包括该字段自己的初始化程序。因此,“ int x = x+1;”不是有效的字段声明。

他还说:

可能会添加一个功能,该功能将像对待匿名类的主体一样专门处理lambda主体(或者,更广泛地说,如果它是变量初始值设定项,则允许lambda引用自身),但这尚未完成。(FWIW,直接修改8.3.2.3并不完全安全,就像第四个项目符号当前并不完全安全:“ 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); 

    /* ... */
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

为什么Java 8中的lambda不允许匿名类不允许成员变量的前向引用?

来自分类Dev

Java中不允许变量声明

来自分类Dev

为什么在通用类型中不允许T类?

来自分类Dev

为什么在通用类型中不允许T类?

来自分类Dev

为什么不允许使用“ this”指针返回成员变量,而允许使用“ this”设置成员变量?

来自分类Dev

为什么在Java中不允许这种向下转换?

来自分类Dev

Java 8为什么不允许接口成员私有?

来自分类Dev

为什么Java 8的注释类型中不允许使用默认方法?

来自分类Dev

为什么在is或as运算符的左侧不允许使用lambda和匿名方法?

来自分类Dev

为什么C ++不允许重新绑定引用?

来自分类Dev

不允许 Java 变量声明

来自分类Dev

为什么在ctor中不允许访问成员对象的成员?

来自分类Dev

为什么不允许ReadWriteLock升级?

来自分类Dev

为什么不允许覆盖

来自分类Dev

为什么Java不允许扩展数组类型

来自分类Dev

为什么不允许仅在一个引用限定符上进行重载?

来自分类Dev

为什么在函数中不允许“从...导入*”?

来自分类Dev

为什么ArrayDeque中不允许使用空值?

来自分类Dev

为什么jooq不允许whenNotMatchedInsert中的记录?

来自分类Dev

为什么C ++中不允许int&a = <value>?

来自分类Dev

为什么在htaccess中不允许重写

来自分类Dev

为什么在Scala中不允许这种匹配?

来自分类Dev

为什么在Erlang的float中不允许使用“ Infinity”?

来自分类Dev

为什么在方案中不允许嵌套定义

来自分类Dev

为什么jooq不允许whenNotMatchedInsert中的记录?

来自分类Dev

为什么 \empty 和 \isset 在 php 中是不允许的

来自分类Dev

为什么不允许在 React 中返回多个元素?

来自分类Dev

ISO C ++ 2003标准中不允许引用引用,但是为什么编译器允许引用呢?

来自分类Dev

为什么在枚举中不允许字段引用(或者这是编译器错误?)

Related 相关文章

  1. 1

    为什么Java 8中的lambda不允许匿名类不允许成员变量的前向引用?

  2. 2

    Java中不允许变量声明

  3. 3

    为什么在通用类型中不允许T类?

  4. 4

    为什么在通用类型中不允许T类?

  5. 5

    为什么不允许使用“ this”指针返回成员变量,而允许使用“ this”设置成员变量?

  6. 6

    为什么在Java中不允许这种向下转换?

  7. 7

    Java 8为什么不允许接口成员私有?

  8. 8

    为什么Java 8的注释类型中不允许使用默认方法?

  9. 9

    为什么在is或as运算符的左侧不允许使用lambda和匿名方法?

  10. 10

    为什么C ++不允许重新绑定引用?

  11. 11

    不允许 Java 变量声明

  12. 12

    为什么在ctor中不允许访问成员对象的成员?

  13. 13

    为什么不允许ReadWriteLock升级?

  14. 14

    为什么不允许覆盖

  15. 15

    为什么Java不允许扩展数组类型

  16. 16

    为什么不允许仅在一个引用限定符上进行重载?

  17. 17

    为什么在函数中不允许“从...导入*”?

  18. 18

    为什么ArrayDeque中不允许使用空值?

  19. 19

    为什么jooq不允许whenNotMatchedInsert中的记录?

  20. 20

    为什么C ++中不允许int&a = <value>?

  21. 21

    为什么在htaccess中不允许重写

  22. 22

    为什么在Scala中不允许这种匹配?

  23. 23

    为什么在Erlang的float中不允许使用“ Infinity”?

  24. 24

    为什么在方案中不允许嵌套定义

  25. 25

    为什么jooq不允许whenNotMatchedInsert中的记录?

  26. 26

    为什么 \empty 和 \isset 在 php 中是不允许的

  27. 27

    为什么不允许在 React 中返回多个元素?

  28. 28

    ISO C ++ 2003标准中不允许引用引用,但是为什么编译器允许引用呢?

  29. 29

    为什么在枚举中不允许字段引用(或者这是编译器错误?)

热门标签

归档