【Java】为什么Java Lambda表达式引用的局部变量需要final修饰

现象

【Java】为什么Java Lambda表达式引用的局部变量需要final修饰

在编写Lambda表达式的时候,有时会引用Lambda表达式以外的变量。

Lambda 表达式引用的局部变量必须是最终变量或实际上的最终变量,也就是说局部变量在被创建后不得被重新赋值。

分析

那么为什么呢?我看了网上的许多文章,写的都比较模糊,例如:

我看的云里雾里,直到我看了这篇文章,【小家java】使用lambda表达式传参是否有性能问题?,里面剖析了Lambda表达式这个语法糖的原理,之后我写了一个Test去验证:

import java.util.function.Consumer;

public class LambdaTest {

Object instanceObj = new Object();

private void test() {

// 用于直接引用

Object localObj1 = new Object();

// 用于传参

Object localObj2 = new Object();

Consumer consumer = (x) -> {

System.out.println(x);

System.out.println(localObj1);

System.out.println(instanceObj);

};

consumer.accept(localObj2);

}

}

之后编译该类,反编译字节码:

javac src/LambdaTest.java

javap -p src/LambdaTest.class

输出:

Compiled from "LambdaTest.java"

public class LambdaTest {

java.lang.Object instanceObj;

public LambdaTest();

private void test();

private void lambda$test$0(java.lang.Object, java.lang.Object);

}

由此可看出,Lambda表达式是一个语法糖,会被编译生成为当前类的一个私有方法,Lambda表达式内直接引用局部变量本质是一种隐式传参,编译时会自动将引用的局部变量放到参数列表中(Lambda方法多了个参数),而引用的实例变量并不需要放到参数列表,因为方法内可以直接引用。


那么造成直接引用的局部变量需要final修饰的原因应该和这种隐式传参有关,所以这里需要再提一下Java方法的传参机制,详见之前发过的Java对象空间占用如何计算?

所以在Lambda中对参数重新赋值或者在方法中将局部变量重新赋值,对另一方都是没有影响的。

结论

因此,为了避免这种误导混淆,保证局部变量和Lambda的变量副本的数据一致性,Java直接在语法层面强制Lambda表达式引用的局部变量不可被重新赋值。


以上剖析仅是我作为一个学习者的个人理解,如有错误欢迎留言进行指正,我们共同进步,谢谢!

感谢您阅读本文,关注我的公众号“语冰Yubing”可接收最新推送,里面也有我分享的一些优质资源。

【Java】为什么Java Lambda表达式引用的局部变量需要final修饰

以上是 【Java】为什么Java Lambda表达式引用的局部变量需要final修饰 的全部内容, 来源链接: utcz.com/a/98930.html

回到顶部