为什么lambda表达式使用的局部变量要是final的

本文探讨了Java中Lambda表达式为何不能访问非final局部变量,揭示了这背后是为了防止数据不同步。同时,详细解释了Lambda如何捕获变量,包括实例变量、静态变量及局部变量,并强调了局部变量需显式或隐式为final。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

为什么 Lambda 表达式(匿名类) 不能访问非 final 类型的局部变量呢?

之前我一直认为是由于Lambda 表达式(匿名类) 会在另一个线程中执行,实例变量存在堆中,而局部变量是在栈上分配,如果在线程中要直接访问一个局部变量,可能线程执行时该局部变量已经被销毁了。

但是有人提出这个原因存在问题,说他们是在同一个线程中运行的,大兄弟提供的验证代码如下:

/**
 * @author xxy
 * @date 2021/4/13
 */
public class Java8Tester {

    public static void main(String[] args) {
        String str = "Hello, ";
        Person person = name -> {
            System.out.println(str + name + "   " + Thread.currentThread().getId());
            System.out.println("匿名类" + "   " + Thread.currentThread().getId());
        };
        System.out.println("主方法" + "   " + Thread.currentThread().getId());
        person.say("JC");
    }

    interface Person {
        void say(String name);
    }
}

运行之后的结果显示确实都是main线程运行的,结果如下:
在这里插入图片描述
我又去看了一些其他的博客,有人说是Java为了防止数据不同步而规定的,也就是为了防止在lambda表达式内使用的外层局部变量被外层代码修改之后内部无法同步这个修改。想看原贴可以点我

非常感谢这位老哥(@JC BLOG)的评论让我能够发现自己的错误,我觉得上面超链接中讲述的原因是比较好的,如果其他同学有不同意见欢迎一起交流一起进步。

Java 8 的 Lambda 可以捕获什么变量呢?

(1). 捕获实例变量或静态变量是没有限制的 (可认为是通过 final 类型的局部变量 this 来引用前两者);

(2). 捕获的局部变量必须显式的声明为 final 或实际效果的的 final 类型
注意(敲黑板):如果在Lambda表达式中使用局部变量,即使我们没有声明成final类型的,编译器也会帮助我们将他们声明成final的,所以如果重新赋值会出错。

如下:
在这里插入图片描述
结果如下:
在这里插入图片描述
此时程序不会报错,虽然我们没有使用final修饰变量b,但是Lambda表达式中也能使用,这是因为编译器帮我们自动声明成final的。

众所周知,final类型的变量不能重新赋值,来验证下是不是编译器真的帮我们声明成了final,如下:
在这里插入图片描述
报错:
在这里插入图片描述
那么是什么时候帮我们声明成final呢?答案是在创建变量的时候直接声明成final的,测试如下:
在这里插入图片描述
在这里插入图片描述

总结:在Lambda表达式中可以捕获静态变量和实例变量,但是如果想要捕获局部变量的时候就需要声明成final的,即使我们不主动声明,编译器也会为我们自动声明成final的,不能再重新赋值。也就是Lambda表达式中访问的局部变量(隐式被声明为final的)是可读不可写的,但是Lambda表达式中访问的实例变量和静态变量是可读可写的。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值