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

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

背景

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

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

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);
    }
}

问题

一开始是编译不过去的

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;对象赋值的方法拷贝出来放到了方法里面

    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中,所以将方法改成如下就可以了

    private static void copyMap(Map<String, List<Phone>> sourceMap, Map<String, List<Phone>> targetMap) {
        targetMap.putAll(sourceMap);
    }


本篇文章如有帮助到您,请给「翎野君」点个赞,感谢您的支持。

目录
打赏
0
0
0
0
12
分享
相关文章
【C++】map、set基本用法
本文介绍了C++ STL中的`map`和`set`两种关联容器。`map`用于存储键值对,每个键唯一;而`set`存储唯一元素,不包含值。两者均基于红黑树实现,支持高效的查找、插入和删除操作。文中详细列举了它们的构造方法、迭代器、容量检查、元素修改等常用接口,并简要对比了`map`与`set`的主要差异。此外,还介绍了允许重复元素的`multiset`和`multimap`。
88 3
【C++】map、set基本用法
|
6月前
|
结合HashMap与Java 8的Function和Optional消除ifelse判断
`shigen`是一位致力于记录成长、分享认知和留住感动的博客作者。本文通过具体代码示例探讨了如何优化业务代码中的if-else结构。首先展示了一个典型的if-else处理方法,并指出其弊端;然后引入了策略模式和工厂方法等优化方案,最终利用Java 8的Function和Optional特性简化代码。此外,还提到了其他几种消除if-else的方法,如switch-case、枚举行、SpringBoot的IOC等。一起跟随shigen的脚步,让每一天都有所不同!
66 10
结合HashMap与Java 8的Function和Optional消除ifelse判断
【Java异常】Variable used in lambda expression should be final or effectively final
【Java异常】Variable used in lambda expression should be final or effectively final
319 0
【Java异常】Variable used in lambda expression should be final or effectively final
TypeError: Cannot set properties of undefined (setting ‘resdata‘),res定义数据出现的问题,定义的方法用this换成that
TypeError: Cannot set properties of undefined (setting ‘resdata‘),res定义数据出现的问题,定义的方法用this换成that
|
10月前
|
.equal()和==的区别 怎样判断字符串为空问题: Illegal invoke-super to void nio.file.AccessDeniedException
.equal()和==的区别 怎样判断字符串为空问题: Illegal invoke-super to void nio.file.AccessDeniedException
js基础语法:包括变量声明、数据类型(Number, String, Boolean, Null, Undefined, Symbol, Object)、运算符、流程控制语句(if...else, switch, for, while, do...while)等。具体案例使用演示
js基础语法:包括变量声明、数据类型(Number, String, Boolean, Null, Undefined, Symbol, Object)、运算符、流程控制语句(if...else, switch, for, while, do...while)等。具体案例使用演示
105 1
玩转ES6(四)Set、Map、Class类和decorator 装饰器
玩转ES6(四)Set、Map、Class类和decorator 装饰器
170 0
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等