首页 > 其他分享 >Variable 'xxxx' is accessed from within inner class, needs to be final or effectively fina

Variable 'xxxx' is accessed from within inner class, needs to be final or effectively fina

时间:2023-07-03 23:55:31浏览次数:44  
标签:needs 变量 作用域 sum 局部变量 list param final

问题的原因

问题代码:

 public static void main(String[] args) {
      Integer sum = 0;
      Integer count = 0;
      List<Integer> list = new ArrayList<>(Arrays.asList(1,2,3,4,5));
      list.stream().forEach(e->{
           sum+=e; //这步会编译错误--Variable used in lambda expression should be final or effectively final
      });
 }

Variable 'xxxx' is accessed from within inner class, needs to be final or effectively final-Lambda 这段话翻译成中文为:变量“xxxx”是从内部类中访问的,需要是final或既成事实上的 final变量。意思就是sum需要为一个final对象或者说既成事实上的 final变量(所谓个既成事实上的 final 变量是指只能给变量赋值一次),如果sum满足以上要求代表sum不能被重新赋值了。

解决方法:

public static void main(String[] args) {
     JSONObject param = new JSONObject();
     param.put("sum",0);
     param.put("count",0);
     List<Integer> list = new ArrayList<>(Arrays.asList(1,2,3,4,5));
     list.stream().forEach(e->{
         param.put("sum",param.getInteger("sum")+e);
         param.put("sum",param.getInteger("count")+1);
     });
}

在外面套一层对象,这里的param就是既成事实上的 final变量,因为在这段代码中param就被赋值过一次。

拓展-访问对象字段与静态变量

Lambda 内部对于实例的字段和静态变量是即可读又可写的。

public class Question2 {
     int sum = 0;
     static int count = 0;
     public static void main(String[] args) {
          Question2 question2 = new Question2();
          List<Integer> list = new ArrayList<>(Arrays.asList(1,2,3,4,5));
          list.stream().forEach(e->{
               question2.sum+=e;
               Question2.count++;
          });
     }
}

小结

Lambda 表达式可以读写实例变量,只能读取局部变量。

思考

  • Lambda 表达式访问非 final 的局部变量,这是为什么呢?
    首先思考外部的局部变量 final 和匿名内部类里面的 final 是否是同一个变量?
    我们知道,每个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接,方法出口等信息,每个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程(《深入理解Java虚拟机》第2.2.2节 Java虚拟机栈)。就是说在执行方法的时候,局部变量会保存在栈中,方法结束局部变量也会出栈,随后会被垃圾回收掉,而此时,内部类对象可能还存在,如果内部类对象这时直接去访问局部变量的话就会出问题,因为外部局部变量已经被回收了,解决办法就是把匿名内部类要访问的局部变量复制一份作为内部类对象的成员变量,查阅资料或者通过反编译工具对代码进行反编译会发现,底层确实定义了一个新的变量,通过内部类构造函数将外部变量复制给内部类变量。
  • 为何还需要用 final 修饰?
    其实复制变量的方式会造成一个数据不一致的问题,在执行方法的时候局部变量的值改变了却无法通知匿名内部类的变量,随着程序的运行,就会导致程序运行的结果与预期不同,于是使用final修饰这个变量,使它成为一个常量,这样就保证了数据的一致性。

参考

https://no8gs.blog.csdn.net/article/details/117333667

标签:needs,变量,作用域,sum,局部变量,list,param,final
From: https://www.cnblogs.com/yuyiming/p/17524487.html

相关文章

  • 27.final和override关键字
    在C++中,final是一个关键字,用于修饰类的成员变量和成员函数。1.final修饰成员变量:当一个类中的成员变量被声明为final时,它就变成了常量,即它的值不能再被修改。final修饰的成员变量必须在类定义中进行初始化,且只能初始化一次。假设我们有一个名为Person的类,其中包含一个成员变量na......
  • classfinal加密java代码并且启动
    maven插件方式配置参数解释: 参数说明-file加密的jar/war完整路径-packages加密的包名(可为空,多个用","分割)-libjarsjar/war包lib下要加密jar文件名(可为空,多个用","分割)-cfgfiles需要加密的配置文件,一般是classes目录下的yml或propertie......
  • finalshell连接超时的解决方法
    CentOS图形管理中的NetworkManager接管了网络配置,可以尝试执行以下命令恢复:systemctlstopNetworkManager临时关闭systemctldisableNetworkManager永久关闭网络管理命令systemctlstartnetwork.service开启网络服务然后在本机中再次使用ping命令,发现可以ping通虚拟机ip,这时......
  • 01-ES6语法:块作用域构造let
    这里所说的ES6是ECMAScript6的简写,它是由JavaScript演变而来的。1996年11月,网景公司将JavaScript提交给欧洲计算机制造商协会(ECMA)进行标准化。ECMA-262的第一个版本于1997年6月被ECMA组织采纳,这也是ECMAScript(简称ES)的由来。块级声明用于声明在指定块的作用域之外无法访问的变量。......
  • JS(函数、作用域、预解析)
    一函数的概念在JS里面,可能会定义非常多的相同代码或者功能相似的代码,这些代码可能需要大量重复使用。虽然for循环语句也能实现一些简单的重复操作,但是比较具有局限性,此时我们就可以使用JS中的函数。函数:就是封装了一段可被重复调用执行的代码块。通过此代码块可以实现大量......
  • 12. Bean 获取,作用域,管理
    Bean获取,作用域,管理默认情况下,spring项目启动时,会把bean都创建好放在IOC容器中,如何想主动获取这些bean,可以通过如下方式获取:getBean()@AutowiredprivateApplicationContextapplicationContext;//IOC容器对象类名lei=(类名)applicationContext.getBean("类名");@Single......
  • 在finally中出现return会发生什么?
    目录看点:面试题:看点:当Java程序执行try块、catch块时遇到了return或throw语句,这两个语句都会导致该方法立即结束,但是系统执行这两个语句并不会结束该方法,而是去寻找该异常处理流程中是否包含finally块,如果没有finally块,程序立即执行return或throw语句,方法终止;如果有finally块,系......
  • The final
    TheendT1构造题n/k为偶数很好构造,每组直接前面拿n/k/2个,后面拿n/k/2个n/k为奇数需要想一想,首先可以把1~n分成n/k段,每段选一个放到一组里,按照以上方法处理n/k-3段,使每组各数之和相等。再来看前三段,可以把第三段提出来,用前1,2段构造一个等差数列。如何构造?只需要找到需要的等差......
  • [极客大挑战 2019]FinalSQL
    https://buuoj.cn/challenges#[%E6%9E%81%E5%AE%A2%E5%A4%A7%E6%8C%91%E6%88%98%202019]FinalSQL测起来有点感觉过滤很奇怪casewhenmidunionif'and-!|...逻辑运算符与、或都测起来有点奇怪,同或因为过滤了!没法用,所以用异或mysql>select0^1;+-----+|0^1|+-----+|......
  • 对象的finalize调用链和clone调用链一样,必须手工构造
    classA{publicA(){System.out.println("Aconstruct");}@Overridepublicvoidfinalize(){System.out.println("Afinalize");}}classBextendsA{String......