今天群里讨论javalambda实现.

后来不断衍生谈到了为什么lambda和匿名内部类只能使用语义final的外部变量.

最开始以为是java的lambda实现问题,编译期魔法会把外部引用作为参数传入所以在内部变化也影响不了下次调用的值,所以就干脆final了,如果用类的属性来保管这个变量就可以了.

In [64]:  def outer(a:int):
...: def inner():
...: nonlocal a
...: a = a + a
...: return a
...: return inner
...: In [65]: x = outer(1) In [66]: x
Out[66]: <function __main__.outer.<locals>.inner> In [67]: x()
Out[67]: 2 In [68]: x()
Out[68]: 4 In [69]: x()
Out[69]: 8

举例就是这种情况

lambda用参数传入外部int,如果在方法里修改了,下次调用这个lambda依旧是以前的值.

后来又去看了眼匿名内部类的实现

public class InnerTest {

    public static void main(String[] args) {
String name = "123";
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println(name);
}
};
r.run();
}
}
 InnerTest$1(java.lang.String val$name);
0 aload_0 [this]
1 aload_1 [val$name]
2 putfield InnerTest$1.val$name : java.lang.String [12]
5 aload_0 [this]
6 invokespecial java.lang.Object() [14]
9 return
Line numbers:
[pc: 0, line: 1]
[pc: 5, line: 11]
Local variable table:
[pc: 0, pc: 10] local: this index: 0 type: new InnerTest(){}
Method Parameters:
final synthetic val$name

构造方法字节码明明都存下来了呀...为什么那时候就要求final

查阅了一下,发现这样有个很大的问题.

这个外部变量在匿名内部类初始化之后就被固定了下来,之后他如果被重新赋值(引用类型内部状态修改除外),就会出现内部无法看见外部,外部也无法看见内部的问题... ...

举个简单的例子:

In [101]: def outer(x):
...: def inner():
...: nonlocal x
...: x = x+1
...: print("inner"+str(x))
...: inner()
...: print("outer"+str(x))
...: x = x+1
...: inner()
...: In [102]: outer(1)
inner2(inner内部+1)
outer2(外部看到这个变化)
inner4(外部+1 内部+1)

这段在py下能正常工作的代码,如果java没有final限制的话,就会变成

inner2(inner内部+1)
outer1(外部看不到inner变化)
inner3(inner内部+1)

所以这个约定和闭包实现没关系...

还是考虑在定义变量的作用域下规避掉因为java实现问题导致上面的结果返回...我既然没有nonlocal这样的机制(毕竟不支持引用传递....),索性就用final限制起来.

呜呼哀哉


参考资料:

https://stackoverflow.com/questions/4732544/why-are-only-final-variables-accessible-in-anonymous-class

Closure_(computer_programming)

lambda和匿名内部类使用外部变量为什么要语义final?的更多相关文章

  1. 为什么Java中lambda表达式不能改变外部变量的值,也不能定义自己的同名的本地变量呢?

    作者:blindpirate链接:https://www.zhihu.com/question/361639494/answer/948286842来源:知乎著作权归作者所有.商业转载请联系作者获得授 ...

  2. 关于Lambda表达式访问外部变量

    在<C#高级编程>一书中提到通过Lambda表达式可以访问Lambda表达式块外部的变量 ,这是一个很好的功能(类似Js中的 闭包).但是如果没有正确的使用,会非常危险. 比如下面的事例中 ...

  3. 匿名内部类中使用的外部局部变量为什么只能是final变量

    被匿名内部类引用的变量会被拷贝一份到内部类的环境中 但其后,在外部,该变量如果被修改,则内部外部不一致 Java为了避免数据不同步的问题,做出了匿名内部类只可以访问final的局部变量的限制. 究其原 ...

  4. python函数定义中引用外部变量的一个问题

    如果在函数定义的默认值中引用了一个外部变量,如下所示 x = 3 def func(a = x): print(a, x) 那么a的默认值就会是3, 但是print语句中的x会是调用时的x值 lamb ...

  5. 为什么内部类调用的外部变量必须是final修饰的?

    感谢原文:https://blog.csdn.net/u010393325/article/details/80643636 因为生命周期的原因.方法中的局部变量,方法结束后这个变量就要释放掉,fin ...

  6. PHP变量入门教程(4)PHP 的外部变量

    PHP 的外部变量 HTML 表单(GET 和 POST) 当一个表单体交给 PHP 脚本时,表单中的信息会自动在脚本中可用.有很多方法访问此信息,例如: 一个简单的 HTML 表单 <form ...

  7. 【C语言】C语言外部变量和内部变量

    目录: [外部变量] · 定义 · 用extern修饰变量 [内部变量] · 定义 · 用static修饰变量 1.外部变量 · 定义 定义的变量能被本文件和其它文件访问的变量,称为外部变量. 注: ...

  8. awk引用外部变量及调用系统命令方法

    目标:想用awk与scp命令批量传送文件 前提:先搭好主机间的免密登陆环境(参考:http://www.cnblogs.com/tankaixiong/p/4172942.html) 实现脚本方法: ...

  9. ajax 外部变量

    1.一般的js代码可以放在任何位置.但是用jquery写的代码需要先引入jquery文件,再写代码. 2.ajax函数中内部的变量不能传到外部.如果改变外部变量,需要async:false,代码如下: ...

随机推荐

  1. ImageMagick简介、GraphicsMagick、命令行使用示例

    http://elf8848.iteye.com/blog/382528 ImageMagick资料 ------------------------------------------------- ...

  2. Python三元运算

    result = 值1 if 条件 else 值2 如果条件为真,result = 值1 如果条件为假, result = 值2.

  3. Git详解及github与gitlab使用

    第一章 关于版本控制 第二章 GIT简介 第三章 GIT安装 第四章 初次运行GIT前配置 第五章 初始化仓库 第六章 GIT命令操作 第七章 GIT分支结构

  4. myeclipse maven tomcat插件 创建web工程

    自从有了云笔记,很久不写博客了.今天写了使用Freemarker静态化JSP页面,索性就发出来.初学,勿喷. 这篇文字以前放在云笔记里,当然里面有很多借鉴网络上的东西,而自己也使用Maven很久了,索 ...

  5. Python安装和配置

    在我厂呆了快一年,终于等来了转岗机会,而且现在正在调动到新成立的AI战略部门,心里无比欣喜和激动.自己作为一个小白,终于有机会踏入AI领域,离自己的梦想更近了一步,个人感到无比的幸运,仿佛天生就有上天 ...

  6. CountDownLatch和CyclicBarrier 区别

    CountDownLatch : 一个线程(或者多个), 等待另外N个线程完成某个事情之后才能执行. CyclicBarrier        : N个线程相互等待,任何一个线程完成之前,所有的线程都 ...

  7. ToB蓝海的台阶-PaaS,SaaS技术详解

    前言 随着大量SaaS公司进入市场,我们看到颠覆性的软件服务以各种方式进入企业流程-从营销工具到支付系统.随着SaaS帮助优化业务流程,实现更流畅和自动化的运营,风险投资公司首先潜入池中寻找最优秀和最 ...

  8. 影响HTTP性能的常见因素

    影响HTTP性能的常见因素 我们这里讨论HTTP性能是建立在一个最简单模型之上就是单台服务器的HTTP性能,当然对于大规模负载均衡集群也适用毕竟这种集群也是由多个HTTTP服务器的个体所组成.另外我们 ...

  9. TIMO后台管理系统-基于SpringBoot开发

    项目介绍 TIMO后台管理系统,基于SpringBoot2.0 + Spring Data Jpa + Thymeleaf + Shiro 开发的后台管理系统,采用分模块的方式便于开发和维护,支持前后 ...

  10. ssm框架搭建和整合流程

    Spring + SpringMVC + Mybatis整合流程 1      需求 1.1     客户列表查询 1.2     根据客户姓名模糊查询 2      整合思路 第一步:整合dao层 ...