Java lambda具有与匿名内部类不同的变量要求 [英] Java lambdas have different variable requirements than anonymous inner classes

查看:112
本文介绍了Java lambda具有与匿名内部类不同的变量要求的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个匿名的内部类和一个等效的lambda。为什么lambda的变量初始化规则更严格,是否有比匿名内部类更清晰的解决方案或在构造函数中初始化它?

I have an anonymous inner class and an equivalent lambda. Why are the variable initialization rules stricter for the lambda, and is there a solution cleaner than an anonymous inner class or initializing it in the constructor?

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 for val

I did run across one workaround: using a getter for val.

推荐答案

关于 lambda表达体状态


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

Unlike code appearing in anonymous class declarations, the meaning of names and the this and super keywords appearing in a lambda body, along with the accessibility of referenced declarations, are the same as in the surrounding context (except that lambda parameters introduce new names).

的透明度(显式和隐式)在
lambda表达式的主体中 - 也就是说,将它与
周围上下文中的相同 - 允许实现更灵活,并且
阻止了身体中不合格的名字因
而异,取决于超载分辨率。

The transparency of this (both explicit and implicit) in the body of a lambda expression - that is, treating it the same as in the surrounding context - allows more flexibility for implementations, and prevents the meaning of unqualified names in the body from being dependent on overload resolution.

因此,它们更加严格。

在这种情况下,周围的上下文是对字段的赋值,而当前的问题是对字段的访问, val ,一个空白 final 字段,位于表达式的右侧。

The surrounding context, in this case, is an assignment to a field and the issue at hand is an access of a field, val, a blank final field, in the right hand side of the expression.

Java语言规范州


每个局部变量(§14.4)和每个空白最终字段(§ 4.12.4,$ b $b§8.3.1.2)当发现其
值的任何访问时必须具有明确赋值。

Each local variable (§14.4) and every blank final field (§4.12.4, §8.3.1.2) must have a definitely assigned value when any access of its value occurs.

访问其value由变量
简单名称组成(或者,对于字段,由限定的字段的简单名称)
出现在表达式的任何地方,除了作为
左手操作数的简单赋值运算符 = (§15.26.1)。

An access to its value consists of the simple name of the variable (or, for a field, the simple name of the field qualified by this) occurring anywhere in an expression except as the left-hand operand of the simple assignment operator = (§15.26.1).

每次访问本地变量或空白最终字段 x x 必须在访问前明确分配
,否则会发生编译时错误。

For every access of a local variable or blank final field x, x must be definitely assigned before the access, or a compile-time error occurs.

然后继续说


C 是一个类,让 V 为空白最终非 - static 成员字段
C ,在 C 中声明。然后:

Let C be a class, and let V be a blank final non-static member field of C, declared in C. Then:


  • V 绝对是未分配的(而且肯定不是在最左边的实例初始化器(第8.6节)或实例变量
    初始化器 C 之前。

  • V is definitely unassigned (and moreover is not definitely assigned) before the leftmost instance initializer (§8.6) or instance variable initializer of C.

V 在实例初始值设定项或实例变量初始化程序 C 之前已经[un]分配最左边的iff V 是在前面的实例初始化程序或实例
变量初始化程序 C [un] c $ c>。

V is [un]assigned before an instance initializer or instance variable initializer of C other than the leftmost iff V is [un]assigned after the preceding instance initializer or instance variable initializer of C.

您的代码基本上看起来像这样

Your code basically looks like this

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 lambdaGetValString 的初始化表达式中访问时未分配。

The compiler therefore determines that val in unassigned when it's access within the initialization expression for lambdaGetValString.

上述规则适用于使用一个简单的名称, val ,而不是一个合格的表达式, this.val 。你可以使用

The rules above apply to the use of a simple name, val, not to a qualified expression, this.val. You can use

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

这篇关于Java lambda具有与匿名内部类不同的变量要求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆