Lambda表达式和变量捕获 [英] Lambda Expression and Variable Capture

查看:241
本文介绍了Lambda表达式和变量捕获的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请向我解释,lambda表达式如何使用和修改它的封闭类的实例变量,只能使用它的封闭范围的局部变量(除非是final或者有效的final)?
我的基本问题是类的实例变量是如何在Lambda中可修改的,局部变量不在范围的上下文中

Please explain to me that how can lambda expression use and modify instance variable of it's enclosing class and can only use local variable of it's enclosing scope.(unless it is final or effective final)? My Basic Question is how instance variable of the class is modifiable within Lambda and local variable is not, in context of scope

推荐答案

首先,我们可以看看 JLS ,其中指出以下内容:

At first, we can take a look at the JLS, which states the following:


任何使用的局部变量,形式参数或异常参数但是没有在lambda表达式中声明必须被声明为final或有效地为final(§4.12.4),否则在尝试使用时出现编译时错误。

Any local variable, formal parameter, or exception parameter used but not declared in a lambda expression must either be declared final or be effectively final (§4.12.4), or a compile-time error occurs where the use is attempted.

在lambda主体之前使用但未声明的任何局部变量必须在lambda主体之前被明确赋值(§16(确定赋值))或编译时错误。

Any local variable used but not declared in a lambda body must be definitely assigned (§16 (Definite Assignment)) before the lambda body, or a compile-time error occurs.

变量使用的类似规则适用于内部类的体(§8.1.3)。对有效的最终变量的限制禁止访问动态变化的局部变量,其捕获可能引入并发问题。与最终限制相比,它减少了程序员的文书负担。

Similar rules on variable use apply in the body of an inner class (§8.1.3). The restriction to effectively final variables prohibits access to dynamically-changing local variables, whose capture would likely introduce concurrency problems. Compared to the final restriction, it reduces the clerical burden on programmers.

有效的最终变量的限制包括标准循环变量,但不是增强型循环变量,被视为循环的每次迭代都是不同的(§14.14.2)。

The restriction to effectively final variables includes standard loop variables, but not enhanced-for loop variables, which are treated as distinct for each iteration of the loop (§14.14.2).






要更好地了解它,请查看此示例类:


To understand it better, take a look at this example class:

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与使用<$ c创建一个新的匿名类是一样的$ c> new Consumer< String>(){...} 。您的lambda - Consumer< String> 的实例具有对其已创建的类的引用。您可以重写returnConsumerWithInstanceVariable以使用 System。 out.println(s + LambdaTest.this.string),这样做完全一样。这就是为什么你被允许访问(和修改)实例变量。

This is because returning a lambda here is much the same as creating a new anonymous class with new Consumer<String>() {...}. Your lambda - an instance of Consumer<String> has a reference to the class it has been created in. You could rewrite the returnConsumerWithInstanceVariable to use System.out.println(s + LambdaTest.this.string), this would do exactly the same. This is why you are allowed to to access (and modify) instance variables.

如果你的方法中有一个(有效的)最终局部变量,你可以访问它,因为您可以访问它,因为它被复制到您的lambda实例。

If you have a (effective) final local variable in your method, you can access it because you can access it because it gets copied to your lambda instance.

但是,如果它不是最终的,你认为应该在以下环境中发生什么: p>

But, however, if its not final, what do you think should happen in the following context:

Consumer<String> returnConsumerBad() {
    String foo = " you there!";
    Consumer<String> results = ((s) -> {System.out.println(s + foo);});
    foo = " to all of you!";
    return results;
}

应该将值复制到您的实例,但是当局部变量是否更新?这可能会导致混乱,因为我认为很多程序员会希望foo在返回这个lambda后会有新的值给所有的人。

Should the value get copied to your instance, but then not get updated when the local variable is updated? That would probably cause confusion, as I think many programmers would expected foo to have the new value "to all of you" after returning this lambda.

如果你有一个原始的价值,它会放在堆栈上。所以你不能简单地引用局部变量,因为它可以在你的方法结束后消失。

If you had a primitive value, it would lay on the stack. So you could not simply reference the local variable, because it could disappear after the end of your method is reached.

这篇关于Lambda表达式和变量捕获的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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