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


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

目录
相关文章
|
3月前
|
网络协议 C++
解决MASM32代码汇编出错: error A2181: initializer must be a string or single item
解决MASM32代码汇编出错: error A2181: initializer must be a string or single item
|
3月前
|
设计模式 Java
结合HashMap与Java 8的Function和Optional消除ifelse判断
`shigen`是一位致力于记录成长、分享认知和留住感动的博客作者。本文通过具体代码示例探讨了如何优化业务代码中的if-else结构。首先展示了一个典型的if-else处理方法,并指出其弊端;然后引入了策略模式和工厂方法等优化方案,最终利用Java 8的Function和Optional特性简化代码。此外,还提到了其他几种消除if-else的方法,如switch-case、枚举行、SpringBoot的IOC等。一起跟随shigen的脚步,让每一天都有所不同!
43 10
结合HashMap与Java 8的Function和Optional消除ifelse判断
|
5月前
|
并行计算 Serverless API
函数计算操作报错合集之出现 "AttributeError: 'NoneType' object has no attribute 'pop'" 错误,是什么原因
在使用函数计算服务(如阿里云函数计算)时,用户可能会遇到多种错误场景。以下是一些常见的操作报错及其可能的原因和解决方法,包括但不限于:1. 函数部署失败、2. 函数执行超时、3. 资源不足错误、4. 权限与访问错误、5. 依赖问题、6. 网络配置错误、7. 触发器配置错误、8. 日志与监控问题。
171 1
|
6月前
|
JavaScript 前端开发 索引
JavaScript有7个数据类型:Number, String, Boolean, Null, Undefined, Symbol(BES6)和BigInt(ES10)组成基本类型
【6月更文挑战第25天】JavaScript有7个数据类型:Number, String, Boolean, Null, Undefined, Symbol(BES6)和BigInt(ES10)组成基本类型,而Object包括Array、Function等是引用类型。Objects可以包含键值对,Array是特殊的Object。Functions也是对象。`null`和`undefined`被视为特殊的原始值。
59 1
TypeError: Cannot set properties of undefined (setting ‘resdata‘),res定义数据出现的问题,定义的方法用this换成that
TypeError: Cannot set properties of undefined (setting ‘resdata‘),res定义数据出现的问题,定义的方法用this换成that
|
存储 Java 编译器
【Java异常】Variable used in lambda expression should be final or effectively final
【Java异常】Variable used in lambda expression should be final or effectively final
260 0
【Java异常】Variable used in lambda expression should be final or effectively final
解决lambda中必须为final的方式
解决lambda中必须为final的方式
207 0
|
7月前
|
存储 编译器 C语言
【C++ 模板编程 实用手段】深入理解 C++ 中的 packaged_task、invoke_result_t、bind、result_of 和 Lambda
【C++ 模板编程 实用手段】深入理解 C++ 中的 packaged_task、invoke_result_t、bind、result_of 和 Lambda
141 0
|
前端开发 JavaScript
玩转ES6(四)Set、Map、Class类和decorator 装饰器
玩转ES6(四)Set、Map、Class类和decorator 装饰器
164 0
|
Java 程序员 编译器
Variable used in lambda expression should be final or effectively final
Variable used in lambda expression should be final or effectively final
Variable used in lambda expression should be final or effectively final