开发者社区> 人语驿边桥> 正文

简单说明:list.forEach 中变量必须为 final 的问题

简介: 可能有些人没遇到过 list.forEach 中变量必须为 final 的问题,那就先举两个例子 示例1,如下: public static void main(String[] args) { List<String> stringList = new ArrayList<>(); stringList.
+关注继续查看

可能有些人没遇到过 list.forEach 中变量必须为 final 的问题,那就先举两个例子

示例1,如下:

public static void main(String[] args) {
    List<String> stringList = new ArrayList<>();
    stringList.add("a");
    stringList.add("b");
    stringList.add("c");
    stringList.add("d");
    int i = 0;
    stringList.forEach(s -> {
        System.out.println(s + i);
    });
}

示例2,如下:

public static void main(String[] args) {
    List<String> stringList = new ArrayList<>();
    stringList.add("a");
    stringList.add("b");
    stringList.add("c");
    stringList.add("d");
    int i = 0;
    stringList.forEach(s -> {
        System.out.println(s + i);
        // 示例1与示例2的区别
        i = i + 1
    });
}

咋一看,两个示例没什么问题,都能正常运行。但是实际运行结果如下。

示例1运行结果

a0
b0
c0
d0

而示例2无法运行,编辑器给了如下提示

Error:(16, 36) java: 从lambda 表达式引用的本地变量必须是最终变量或实际上的最终变量

要把示例2修正为可以运行的代码,可以做如下修正:

public static void main(String[] args) {
    List<String> stringList = new ArrayList<>();
    stringList.add("a");
    stringList.add("b");
    stringList.add("c");
    stringList.add("d");
    final int[] i = {0};
    stringList.forEach(s -> {
        System.out.println(s + i[0]);
        i[0] = i[0] + 1;
    });
}

就以上的现象,用三个问题来简单说明。

问题一,为什么示例2的 int i = 0 必须用 final 修饰?

答:forEach 在此处使用的是 lambda 表达式,可以简单的把 lambda 表达式 理解为匿名内部类(lambda 表达式不仅仅是内部类这么简单)。而匿名内部类的变量必须用 final 修饰。

问题二,为什么匿名内部类的变量必须用 final 修饰?

答:类的生命周期比方法的生命周期长,同理匿名类的生命周期比方法的生命周期长。换句话说,方法运行完了,变量释放了,但是匿名内部类还在。这时就要求匿名内部类引用的变量必须还在,这样才能保持数据的一致性。

问题三,为什么变量 int i 要改为数组 int[] i?

答:因为 final int i 中,i 的值是无法改变的,但是方法中需要一个可以改变的变量。在 final int[] i 中,i 的引用地址是不变的,但是 i 的属性是可以改变的。

以上只是简单的说明,便于大家理解。大家可以继续深究一下里面的知识点。


如果文章有帮助到了你,欢迎点赞、转发。

如果文章有错误的地方,欢迎留言交流。

image

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
Microsoft Visual Studio与Firefly 一直提示加载项目,更新源码状态问题
        笔记本一开始安装的是vs2010,由于近期开发要用vs2008与vs2005于是今天又把2008、2005安装上了,但在打开项目的时候,先是提示加载项目文件,然后一直提示更新源码状态,很慢很慢的,之前只有vs2010的时候,打开是很快的,现在不管是用2008、2005、2010就没有一个快的,源码管理用的是firefly,有人知道为什么会出现这种情况吗?        
1017 0
【PHP】数组foreach引发的小问题
Code $arr1 = [ 1, 2, 3, 4, 5 ]; $arr2 = [ 'a', 'b', 'c', 'd', 'e' ]; $arr3 = []; foreach ($arr1 as & $v){ $v += 10; } foreach ($arr2 as $k => $v){ //举例 $v = $v .
570 0
简单说明:list.forEach 中变量必须为 final 的问题
可能有些人没遇到过 list.forEach 中变量必须为 final 的问题,那就先举两个例子 示例1,如下: public static void main(String[] args) { List<String> stringList = new ArrayList<>(); stringList.
2273 0
阿里云账号实名认证个人和企业的区别及潜在问题说明
阿里云账号实名认证分为个人认证和企业认证,阿里云个人认证和企业认证有什么区别?阿里云企业账号可以使用个人个人实名认证吗?阿小云来详细说下
2751 0
基于Knox登录Yarn UI查看SparkStreaming作业兼容性问题说明
问题背景 1.登录EMR集群节点,运行SparkStreaming示例,如下所示(不同版本EMR集群spark-examples_xxx.jar的路径略有差异): [root@emr-header-1 ~]# spark-submit --class org.
1668 0
PHP获取当前url路径的函数及服务器变量:QUERY_STRING、REQUEST_URI、SCRIPT...
1,$_SERVER["QUERY_STRING"]说明:查询(query)的字符串 2,$_SERVER["REQUEST_URI"]说明:访问此页面所需的URI 3,$_SERVER["SCRIPT_NAME"]说明:包含当前脚本的路径 4,$_SERVER["PHP_SELF"]说明:当前正在执行脚本的文件名 实例:1,http://www.
867 0
+关注
人语驿边桥
主要从事 Java 后端开发。
41
文章
124
问答
来源圈子
更多
+ 订阅
文章排行榜
最热
最新
相关电子书
更多
OceanBase 入门到实战教程
立即下载
阿里云图数据库GDB,加速开启“图智”未来.ppt
立即下载
实时数仓Hologres技术实战一本通2.0版(下)
立即下载