lambda表达式或者匿名函数中为什么要求外部变量为final

1、参考博客

  1. 关于Lambda表达式里面修改外部变量问题
  2. JDK8之前,匿名内部类访问的局部变量为什么必须要用final修饰

2、匿名内部类

在jdk7之前,匿名内部类访问外部类的局部变量时,那么这个局部变量必须用final修饰符修饰,如下图1所示。jdk8则不需要,但是我们在使用这个局部变量时,无法改变局部变量的值,否则编译会报错。
jdk7之前使用匿名函数
这个特点为什么要求是final类的呢?
因为在java设计之初为了保护数据的一致性而规定的。对引用变量来说是引用地址的一致性,对基本类型来说就是值的一致性。

注意:在JDK8之后,匿名内部类引用外部变量时虽然不用显式的用final修饰,但是这个外部变量必须和final一样,不能被修改(这是一个坑)。解决方案:可以通过定义一个相同类型的变量b,然后将该外部变量赋值给b,匿名内部类引用b就行了,然后就可以继续修改外部变量。

3、lambda表达式

这是因为:Java会将result的值作为参数传递给Lambda表达式,为Lambda表达式建立一个副本,它的代码访问的是这个副本,而不是外部声明result变量。可能很多同学会问为什么非要建立副本呢,直接访问外部的result变量得多方便呢。答案是:这是不可能滴,因为result定义在栈中,当Lambda表达式被执行的时候,result可能已经被释放掉了。

当然啦,你要是一定要在Lambda表达式里面修改外部变量的值也是可以的,可以将变量
定义为实例变量或者将变量定义为数组。

① 情形一

如下图所示:在使用外部类的局部变量时,如果试图修改值,就会编译报错。
在使用lambda表达式

② 情形二

如果局部变量是对象类型,则对象的引用地址不可改变,如下图所示。但是如果在局部变量中修改对象是没有问题的(第二篇博客有详细解释)。
在这里插入图片描述

③ 情形三

在项目中,我遇到过这种情况:有两个集合,我先对一个集合进行遍历,在这里面又需要对另外一个集合遍历。当时出现了编译报错:variable used in lambda expression should be final or effectively final(lambda表达式中使用的变量应该是final或effective final),位置在下图的红框内。如下图所示。但是下图当我工作之余究其缘由调试时的demo,此时编译又不报错了。我能力有限,暂时还不清楚问题出现的原因。当时我的解决方案有两个:一个是在将lambda表达式换成了for下标遍历,就OK了。另一种方案是创建一个报错的同类型新对象,将list1的引用赋值给新对象,编译也不报错了(如下下图所示)。
在这里插入图片描述
在这里插入图片描述

4、总结

本文简单介绍了匿名内部类以及lambda表达式中,引入外部变量时要求为final类型,做了简单的总结。LZ借鉴了他人的博客,加上自己的理解、测试,整理了这篇文章。在开头已经贴出原文地址,若果有错误,万望l留言指正;如果涉及侵权,请联系本人删除。

  • 7
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值