问题的原因

问题代码:

 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

Variable 'xxxx' is accessed from within inner class, needs to be final or effectively final-Lambda 表达式的变量与作用域的更多相关文章

  1. Variable used in lambda expression should be final or effectively final

    Lambda与匿名内部类在访问外部变量时,都不允许有修改变量的倾向,即若: final double a = 3.141592; double b = 3.141592; DoubleUnaryOpe ...

  2. Eclipse连接数据库报错Local variable passwd defined in an enclosing scope must be final or effectively final

    其实原因很简单,就是翻译的结果 匿名内部类和局部内部类只能引用外部的fianl变量 把变量变成fianl就行了  第一次知道啊    记小本本.......

  3. Python中变量的作用域(variable scope)

    http://www.crifan.com/summary_python_variable_effective_scope/ 解释python中变量的作用域 示例: 1.代码版 #!/usr/bin/ ...

  4. mysql碰到unknown variable 'xxxx' 的解决方法

    在使用mysqlbinlog查看日志的时候碰到了一个问题, 错误提示如下: /usr/local/mysql/bin/mysqlbinlog: unknown variable 'default-ch ...

  5. Missing URI template variable 'XXXX' for method parameter of type String

    原因:就是spring的controller上的@RequestMapping的实参和方法里面的形参名字不一致 方法:改成一样就可. ps.还能用绑定的方法,不建议,因为太麻烦了 @RequestMa ...

  6. Linq之Lambda进阶

    目录 写在前面 系列文章 带有标准查询运算符的Lambda Lambda中类型推断 Lambda表达式中变量作用域 异步Lambda 总结 写在前面 上篇文章介绍了Lambda的基本概念以及匿名方法, ...

  7. Java 8 Lambda 表达式(一)

    Java 8 新特性 Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性. Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中). 使用 Lambda 表 ...

  8. JDK各个版本的新特性jdk1.5-jdk8

    JDK各个版本的新特性 对于很多刚接触java语言的初学者来说,要了解一门语言,最好的方式就是要能从基础的版本进行了解,升级的过程,以及升级的新特性,这样才能循序渐进的学好一门语言.今天先为大家介绍一 ...

  9. JDK各版本新特性!

    1.JDK1.5 新特性 1.自动装箱与拆箱:自动装箱的过程:每当需要一种类型的对象时,这种基本类型就自动地封装到与它相同类型的包装中.自动拆箱的过程:每当需要一个值时,被装箱对象中的值就被自动地提取 ...

  10. jdk版本比较

    JDK各个版本的新特性 对于很多刚接触java语言的初学者来说,要了解一门语言,最好的方式就是要能从基础的版本进行了解,升级的过程,以及升级的新特性,这样才能循序渐进的学好一门语言.今天先为大家介绍一 ...

随机推荐

  1. [C++基础入门] 3、 运算符

    文章目录 3 运算符 3.1 算术运算符 3.2 赋值运算符 3.3 比较运算符 3.4 逻辑运算符 3 运算符 **作用:**用于执行代码的运算 本章我们主要讲解以下几类运算符: 运算符类型 作用 ...

  2. Python 持久化-文件

    文件 长久保存信息的一种数据信息集合 常用操作 打开关闭(文件一旦打开,需要关闭操作) 读写内容 查找 open函数 open函数负责打开文件,带有很多参数 第一个参数: 必须有,文件的路径和名称 m ...

  3. XMake学习笔记(1):Windows(MSYS2)下MinGW-w64环境搭建和XMake安装

    以前写的C++基本都是C with STL,大多是面向过程的算法题,或者比较小的项目,然后经常报各种编译错误(对编译原理不熟),经常把人搞到崩溃,搞不懂构建.链接之类的东西. 现在开始记录一下XMak ...

  4. cryptohack wp day(4)

    接上题 第五题(Modular Inverting) 在模运算中,如果我们要解决形如a * x ≡ b mod m的方程,其中a,b,m是已知整数,x是未知整数,我们可以使用扩展欧几里得算法来找到x的 ...

  5. 谁想和我一起做低代码平台!一个可以提升技术,让简历装x的项目

    序言 正如文章标题所述,最近一段时间低代码这个概念非常的火,但其实在不了解这个东西的时候觉得它真的很炫酷,从那时就萌生了做一个低代码平台的想法. 但随着时间的变化,现在市面上低代码各个业务方向的平台都 ...

  6. 2022-10-02:以下go语言代码能否通过编译?A: 能;B: 不能;C: 不知道。 package main import ( “fmt“ ) type worker interfa

    2022-10-02:以下go语言代码能否通过编译?A: 能:B: 不能:C: 不知道. package main import ( "fmt" ) type worker int ...

  7. ChatGPT Plugin开发setup - Java(Spring Boot) Python(fastapi)

    记录一下快速模板,整体很简单,如果不接auth,只需要以下: 提供一个/.well-known/ai-plugin.json接口,返回openAI所需要的格式 提供openAPI规范的文档 CORS设 ...

  8. select_related一对一、多对一查询优化

    select_related一对一.多对一查询优化 Course.objects.all().select_related('teacher') 查询课程时顺带查出老师的信息

  9. Cesium中监听MOUSE_MOVE事件获取经纬度和高度

    有时候在这个圆球上获取精确的经度纬度还不容易,特别是高度 还好在cesium提供了接口,看 let selft = this; const scene = this.viewer.scene; var ...

  10. 执行pod setup 报错error: RPC failed; curl 18 transfer closed with outstanding read data remainin

    执行pod setup 报错 error: RPC failed; curl 18 transfer closed with outstanding read data remaining fatal ...