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


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

目录
相关文章
|
23小时前
|
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`被视为特殊的原始值。
7 1
|
8月前
|
存储 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
103 0
【Java异常】Variable used in lambda expression should be final or effectively final
|
7月前
解决lambda中必须为final的方式
解决lambda中必须为final的方式
91 0
|
1月前
|
存储 编译器 C语言
【C++ 模板编程 实用手段】深入理解 C++ 中的 packaged_task、invoke_result_t、bind、result_of 和 Lambda
【C++ 模板编程 实用手段】深入理解 C++ 中的 packaged_task、invoke_result_t、bind、result_of 和 Lambda
47 0
|
1月前
|
缓存 Java
equal 和 == 在对象、变量类型下的不同情况
equal 和 == 在对象、变量类型下的不同情况
23 0
|
11月前
|
存储 SQL API
VB中判断空的几种方法,Null, Missing, Empty, Nothing, vbNullString区别
VB中判断空的几种方法,Null, Missing, Empty, Nothing, vbNullString区别
|
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
在main函数中创建新对象时出错 No enclosing instance of type ooo is accessible. Must qualify the allocation with a
在main函数中创建新对象时出错 No enclosing instance of type ooo is accessible. Must qualify the allocation with a
在main函数中创建新对象时出错 No enclosing instance of type ooo is accessible. Must qualify the allocation with a
|
Java
Java - Lambda Error:Variable used in lambda expression should be final or effectively final
Java - Lambda Error:Variable used in lambda expression should be final or effectively final
1506 0
Java - Lambda Error:Variable used in lambda expression should be final or effectively final
使用 some , every ,和 Object.values 检查对象内的值
使用 some , every ,和 Object.values 检查对象内的值
145 0
使用 some , every ,和 Object.values 检查对象内的值