Abu*_*que 11 java variables lambda expression scope
请向我解释一个lambda表达式如何使用和修改其封闭类的实例变量,但只能使用其封闭范围的局部变量.(除非是最终的或有效的决赛?)
我的基本问题是,在范围的上下文中,类的实例变量如何在lambda中可修改而局部变量不可修改.
Ale*_*lex 10
首先,我们可以看看JLS,它说明了以下内容:
使用但未在lambda表达式中声明的任何局部变量,形式参数或异常参数必须声明为final或者是有效的final(§4.12.4),否则在尝试使用时会发生编译时错误.
必须在lambda体之前明确赋值(§16(Definite Assignment)),否则在lambda体中使用但未声明的任何局部变量,或发生编译时错误.
关于变量使用的类似规则适用于内部类的主体(第8.1.3节).对有效最终变量的限制禁止访问动态变化的局部变量,其捕获可能会引入并发问题.与最终限制相比,它减少了程序员的文书负担.
对有效最终变量的限制包括标准循环变量,但不包括增强型循环变量,循环变量被视为循环的每次迭代都是不同的(第14.14.2节).
要更好地理解它,请看一下这个示例类:
public class LambdaTest {
    public static void main(String[] args) {
        LambdaTest test = new LambdaTest();
        test.returnConsumer().accept("Hello");
        test.returnConsumerWithInstanceVariable().accept("Hello");
        test.returnConsumerWithLocalFinalVariable().accept("Hello");
    }
    String string = " world!";
    Consumer<String> returnConsumer() {
        return ((s) -> {System.out.println(s);});
    }
    Consumer<String> returnConsumerWithInstanceVariable() {
        return ((s) -> {System.out.println(s + string);});
    }
    Consumer<String> returnConsumerWithLocalFinalVariable() {
        final String foo = " you there!";
        return ((s) -> {System.out.println(s + foo);});
    }
}
主要的输出是
Hello
Hello world!
Hello you there!
这是因为在这里返回lambda与创建一个新的匿名类非常相似new Consumer<String>() {...}.你的lambda  - 一个实例Consumer<String>有一个对它所创建的类的引用.你可以重写returnConsumerWithInstanceVariable来使用returnConsumerWithInstanceVariable(),这将完全相同.这就是允许您访问(和修改)实例变量的原因.
如果方法中有(有效)最终局部变量,则可以访问它,因为它可以访问它,因为它会被复制到lambda实例.
但是,如果它不是最终的,你认为应该在以下背景下发生什么:
Consumer<String> returnConsumerBad() {
    String foo = " you there!";
    Consumer<String> results = ((s) -> {System.out.println(s + foo);});
    foo = " to all of you!";
    return results;
}
值是否应该复制到您的实例,但是在更新局部变量时不会更新?这可能会引起混淆,因为我认为许多程序员会在返回这个lambda后期望foo为你们所有人提供新值.
如果你有一个原始值,它将放在堆栈上.所以你不能简单地引用局部变量,因为它可能在你的方法结束后消失.
| 归档时间: | 
 | 
| 查看次数: | 12672 次 | 
| 最近记录: |