之前写了一篇 Lambda 的入门文章,有小伙伴很认真地参考着学习了一下,并且在学习的过程中提出了新的问题:“老哥,当我在使用 Lambda 表达式中使用变量的时候,编译器提醒我‘Local variable limit defined in an enclosing scope must be final or effectively final’,意思就是‘从 Lambda 表达式引用的本地变量必须是最终变量或实际上的最终变量’,这其中的 final 和 effectively final 到底有什么区别呢?”

看到这个问题,我忍不住调皮了,不假思索地回答说:“当然是 effectively 啦!”

那老弟竟然没被我气晕过去,紧接着说:“老哥,我知道你幽默,你风趣,这节骨眼你能不能细致给我说说这两者之间的区别啊?在线等。”

然后我细细致致地又给他聊了半个多小时,总算是解释清楚了。临了,他还特意叮嘱我说:“老哥,别忘了写篇文章啊!让更多的小伙伴知道这个区别。”

现在的年轻人啊,真特么有心,未来是你的!我承认我是个负责任的男人,既然如此,下面我就来详细地谈一谈 final 和 effectively final 之间的区别。

先来看看官方(Java 8 的规格说明书)是怎么说的,如下:

a final variable can be defined as An entity once that cannot be changed nor derived from later and an effectively final defined as variable or parameter whose value is never changed after it is initialized is effectively final.

就像你看到的,上面这段解释并没有针对关键词“effectively”进行详细的说明——看得云里雾里的,等于没看。

来看下面这段代码:

int limit = 10;
Runnable r = () -> {limit = 5;for (int i = 0; i < limit; i++) {System.out.println(i);}
};
new Thread(r).start();

编译器会提醒我们“Lambda 表达式中的变量必须是 final 或者 effectively final”,按照编译器的提示,我们把 limit 变量修饰为 final,但这时候,编译器提示了新的错误。

这次的错误就很明确了,final 变量是不能被重新赋值的——众所周知,这正是 final 关键字的作用——于是我们把 limit = 5 这行代码去掉。

final int limit = 10;
Runnable r = () -> {for (int i = 0; i < limit; i++) {System.out.println(i);}
};
new Thread(r).start();

考虑到 limit 在接下来的代码中并未被重新赋值,我们可以将 final 关键字去掉。

int limit = 10;
Runnable r = () -> {for (int i = 0; i < limit; i++) {System.out.println(i);}
};
new Thread(r).start();

代码仍然可以正常编译,正常运行,那么此时的 limit 变量就是“effectively final”的。由于 limit 在接下来的代码中没有被重新赋值,编译器就被欺骗了,想当然地认为 limit 就是一个 final 变量(实际上的最终变量)。

假如 limit 在声明为普通的变量(没有 final 修饰)后又被重新赋值了,那也就不可能成为“effectively final”了。

因此得出的结论是,“effectively final”是一个行为类似于“final”的变量,但没有将其声明为“final”变量,关键就在于编译器是怎么看待的。

好了,我亲爱的读者朋友,以上就是本文的全部内容了。喜欢的话,就点个赞

老哥,Java 中 final 和 effectively final 到底有什么区别?相关推荐

  1. java中的NIO和IO到底是什么区别?20个问题告诉你答案

    摘要:NIO即New IO,这个库是在JDK1.4中才引入的.NIO和IO有相同的作用和目的,但实现方式不同,NIO主要用到的是块,所以NIO的效率要比IO高很多. 本文分享自华为云社区<jav ...

  2. Java中的public static final来修饰数组与接口变量

    Java中的public static final来修饰数组与接口变量 public static final来修饰数组 final对数组的作用 怎样实现对数组的public static final ...

  3. java堆和栈 常量池_GitHub - han-guang-xue/difference-of-stack-heap-pool: Java中堆、栈和常量池的区别...

    Java中堆.栈和常量池的区别 栈 堆 常量池的概念 首先我们先了解一下概念,Java把内存分成两种,一种叫做栈内存,一种叫做堆内存. 栈内存 存放基本类型的变量数据和对象类型的引用(请注意存放的是引 ...

  4. Java中,一切皆是对象——java中的对象类型与基本数据类型的区别

    起因:取一个list给另一个list赋值,然后在另一个list中取出进行修改.list其中类型为对象时,String时,基本数据类型时. [java中的对象类型与基本数据类型的区别] #声明和实例化 ...

  5. Java中Array和ArrayList之间的9个区别

    array和ArrayList都是Java中两个重要的数据结构,在Java程序中经常使用. 即使ArrayList在内部由数组支持,了解Java中的数组和ArrayList之间的差异对于成为一名优秀的 ...

  6. java中list,set,map集合的区别,及面试要点

    Map集合:链接: Map集合的五种遍历方式及Treemap方法 Set集合:链接: Java中遍历Set集合的三种方法 TreeSet集合:链接: Java深入了解TreeSet,和迭代器遍历方法 ...

  7. java中属性是什么意思啊_Java中的字段和属性到底有什么区别?

    Java中的字段和属性到底是什么?他们的含义真的是相同的吗?如果不同,那他们到底又分别是何含义呢? 相信上面的问题,对于很多Java初学者都是相当困惑的,但是好像把他们理解为一个含义也没啥问题,很多J ...

  8. java中的native方法性能到底怎么样?

    前言 java中的native方法性能到底怎么样? 第一次写博客,如果写的不好,望见谅,烦请指出问题,虚心学习 先说结论,native 方法性能不如java方法 一.native方法? 主要是java ...

  9. java中*和**的作用 以及 /和/*和/**的区别

    一.java中*和**的作用 "*"就表示了所有的文件,但是"*"并不包括子目录下的文件: "**"匹配包含任意级子目录中所有的文件: 二. ...

  10. 解析java中方法的重载和重写之间的区别与联系

    解析java中方法的重载和重写之间的区别与联系 1 不同点 1.1 方法重写是在不同的类中(父子类),方法重载是在同一类中 1.2 方法重载最初的目的是构造方法的多样化,方法重写的目的是让重写的方法满 ...

最新文章

  1. 苹果服务器消息转发,iphone-与APNS服务器进行交互以将推送通知发...
  2. opencv摄像头 vmware虚拟机出现select timeout
  3. 杨老师的新课!数学应用
  4. 【Tools】MarkDown教程(四)-MarkDown中的UML图
  5. js页面排序-----基础篇
  6. Kotlin之函数作为参数传递
  7. ​​An Image is Worth 16x16 Words,那么一个视频是什么呢?阿里达摩院用STAM给你答案!...
  8. php5配置与IIS中isapi筛选器不能加载PHP的解决办法
  9. html5读取umd,教程:使用umd、commonjs和es三种模式制作自己的React 组件(库)
  10. 图像预处理——对数变换
  11. 将列表类型的数据转换为树形数据
  12. biztalk 2006 事务补偿模型[翻译]
  13. 通过几道CTF题学习yii2框架
  14. agx上搭建ros2
  15. 实现点击不同的按钮显示不同的内容【同一页面】web
  16. Git 出错error: Pulling is not possible because you have unmerged files
  17. 关于数据的封包发送和拆包使用
  18. WiFi、WiMAX、WBMA与3G的比较
  19. 《商业区块链》作者评论:区块链行业标准的讨论必将是一场持久战
  20. 互联网创业人士具备的5大素质

热门文章

  1. OSChina 周五乱弹 —— 毁人不倦的大师们
  2. scala的linearization
  3. C++描述 1113. 红与黑
  4. 图形驱动程序和显卡驱动什么区别_更新电脑显卡驱动有什么作用 更新电脑显卡驱动操作介绍【详解】...
  5. 20.Consent Controller Get请求逻辑实现
  6. 妙!云服务器远程登录,本地听声音
  7. 线程安全注解——GUARDED_BY
  8. Importance Weighted Adversarial Nets for Partial Domain Adaptation
  9. 京东方恢复给苹果供应OLED面板,到底扯下了谁的遮羞布?
  10. $.ajax返回报错,请求ajax报错 返回readyState0