Java lambda与匿名内部类具有不同的变量要求

大卫·埃尔曼:

我有一个匿名内部类和一个等效的lambda。为什么对于lambda来说,变量初始化规则要严格一些,还有没有比匿名内部类或在构造函数中初始化的解决方案更干净的解决方案?

import java.util.concurrent.Callable;

public class Immutable {
    private final int val;

    public Immutable(int val) { this.val = val; }

    // Works fine
    private final Callable<String> anonInnerGetValString = new Callable<String>() {    
        @Override
        public String call() throws Exception {
            return String.valueOf(val);
        }
    };

    // Doesn't compile; "Variable 'val' might not have been initialized"
    private final Callable<String> lambdaGetValString = () -> String.valueOf(val);
}

编辑:我确实遇到了一种变通方法:对使用getter val

Sotirios Delimanolis:

关于lambda表达主体的章节指出

与出现在匿名类声明中的代码不同,在lambda正文中出现的名称和thisand super关键字的含义以及引用声明的可访问性与周围环境相同(除了lambda参数引入新名称)。

thislambda表达式主体(无论是显式的还是隐式的)透明性(即与周围环境相同)将为实现提供更大的灵活性,并防止主体中不合格名称的含义依赖于重载分辨率。

因此,它们更加严格。

在这种情况下,周围的上下文是对字段的分配,而当前的问题是在表达式右侧访问字段val,即空白final字段。

Java语言规范规定

final在访问任何值时,每个局部变量(第14.4节)和每个空白字段(第4.12.4节,第8.3.1.2节)都必须具有一个明确分配的值。

对它的值的访问包括变量简单名称(或者,对于字段,由限定的字段的简单名称this)出现在表达式中的任意位置,但作为简单赋值运算符的左侧操作数=(第15.26节)。 1)。

对于局部变量或空白final字段的每次访问xx必须在访问之前明确分配,否则会发生编译时错误。

然后继续说

C是一个类,并让V是一个空白的finalstatic成员领域C,中声明C然后:

  • V在的最左实例初始化器(第8.6节)或实例变量初始化器之前绝对未分配(并且也未明确分配)C

  • VC在最左边的iff 的实例初始值设定项或实例变量初始值设定项之前[un]分配,在的前一个实例初始值设定项或实例变量初始值设定项V之后[un]赋值C

您的代码基本上如下所示

private final int val;
// leftmost instance variable initializer, val still unassigned 
private final Callable<String> anonInnerGetValString = ...
// still unassigned after preceding variable initializer
private final Callable<String> lambdaGetValString = ...

因此,编译器val在访问的初始化表达式中时将其分配为unassigned lambdaGetValString

以上规则适用于简单名称的使用val,不适用于限定表达式this.val您可以使用

final Callable<String> lambdaGetValString = () -> String.valueOf(this.val);

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

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

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章