前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >规避Variable used in lambda expression should be final or effectively final而引发了方法参数值拷贝的问题

规避Variable used in lambda expression should be final or effectively final而引发了方法参数值拷贝的问题

作者头像
翎野君
发布2023-05-12 20:24:39
6440
发布2023-05-12 20:24:39
举报
文章被收录于专栏:翎野君翎野君

背景

今天组里面有一个新同事小A向我求助了一个问题,比较典型也是新人很容易犯的问题,特此记录下来。

他写了一个类似于下面的代码

代码语言:javascript
复制
package com.lingyejun.dating.chap11.toutiao;

import java.util.*;
import java.util.stream.Collectors;

public class StreamMapCopy {

    public static List<Phone> initPhoneList() {
        List<Phone> phones = new ArrayList<>();
        Phone phone1 = new Phone(1, "iPhone 11 Pro", "银色", "64GB", 8699);
        Phone phone2 = new Phone(2, "iPhone 11 Pro", "银色", "64GB", 8700);
        Phone phone3 = new Phone(3, "iPhone 11 Pro Max", "银色", "64GB", 8900);

        phones.add(phone1);
        phones.add(phone2);
        phones.add(phone3);

        return phones;
    }

    public static void main(String[] args) {

        List<String> queryPhoneNameList = Arrays.asList("iPhone 11 Pro", "HuaWei", "Oppo", "Vivo");

        Map<String, List<Phone>> otherMap = new HashMap<>();

        if (queryPhoneNameList.size() > 0) {

            Map<String, List<Phone>> phoneMap = initPhoneList().stream()
                    .filter(a -> queryPhoneNameList.contains(a.getProductName()))
                    .collect(Collectors.groupingBy(Phone::getProductName));

            // 这种写法下面的forEach循环中使用到的otherMap编译不过去,
            // Variable used in lambda expression should be final or effectively final
            //otherMap = phoneMap;

            // 将逻辑放到方法中可以绕过此逻辑
            copyMap(otherMap, phoneMap);

        }

        queryPhoneNameList.forEach(queryPhoneName -> {
            otherMap.get(queryPhoneName);
        });

    }

    private static void copyMap(Map<String, List<Phone>> sourceMap, Map<String, List<Phone>> targetMap) {
        // 方法参数是值传递,故这种赋值是不会生效的
        targetMap = sourceMap;
        // 改为下面的方式就可以了
        targetMap.putAll(sourceMap);
    }
}

问题

一开始是编译不过去的

代码语言:javascript
复制
Variable used in lambda expression should be final or effectively final

翻译过来就是说在lambda表达式中只能引用标记了 final 的外层局部变量或者虽然没有显式定义为final,但实际上就是一个final变量,否则会编译错误。

那么显然在上面的代码中的otherMap变量,在Map<String, List<Phone>> otherMap = new HashMap<>();初始化以后,又进行了一次赋值操作otherMap = phoneMap;进行了二次修改,所以编译器认为这不是一个final变量故而报错。

但是我们可以用一些技巧来规避掉这个报错,比如小A的写法,他将otherMap = phoneMap;对象赋值的方法拷贝出来放到了方法里面

代码语言:javascript
复制
    private static void copyMap(Map<String, List<Phone>> sourceMap, Map<String, List<Phone>> targetMap) {
        targetMap = sourceMap;
    }

然后问题就出现了,小A debug了一下发现执行完copyMap(phoneMap, otherMap);之后otherMap仍然是空的,然后翎野君一下子看出了其中的门道,然后给他讲了一下java中方法参数传递实际上是值传递的,之前还专门写过一篇文章辨析Java方法参数中的值传递和引用传递

将这个文章看完相信大家就懂得了其中的原有,因为Map有putAll().它把一个Map的所有元素全部复制到另一个Map中,所以将方法改成如下就可以了

代码语言:javascript
复制
    private static void copyMap(Map<String, List<Phone>> sourceMap, Map<String, List<Phone>> targetMap) {
        targetMap.putAll(sourceMap);
    }

首发链接:https://cloud.tencent.com/developer/article/2285724

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-01-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • 问题
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档