background
Today, A new colleague in the group, Xiao A, asked me for help. It is A typical problem that newcomers are easy to make. I hereby record it.
He wrote a code similar to the following
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", "silver", "64GB", 8699); Phone phone2 = new Phone(2, "iPhone 11 Pro", "silver", "64GB", 8700); Phone phone3 = new Phone(3, "iPhone 11 Pro Max", "silver", "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)); // In this way, the otherMap used in the forEach loop below cannot be compiled, // Variable used in lambda expression should be final or effectively final //otherMap = phoneMap; // This logic can be bypassed by putting logic into a method copyMap(otherMap, phoneMap); } queryPhoneNameList.forEach(queryPhoneName -> { otherMap.get(queryPhoneName); }); } private static void copyMap(Map<String, List<Phone>> sourceMap, Map<String, List<Phone>> targetMap) { // Method parameters are passed by value, so this assignment will not take effect targetMap = sourceMap; // Just change it to the following way targetMap.putAll(sourceMap); } }
problem
It was impossible to compile at first
Variable used in lambda expression should be final or effectively final
In other words, only the outer local variable marked final can be referenced in the lambda expression, or although it is not explicitly defined as final, it is actually a final variable, otherwise there will be a compilation error.
Obviously, the otherMap variable in the above code is in map < string, list < phone > > otherMap = new HashMap < > (); After initialization, another assignment operation is performed. otherMap = phoneMap; It has been modified twice, so the compiler thinks this is not a final variable, so it reports an error.
However, we can use some skills to avoid this error report, such as the writing method of Xiao A, who puts otherMap = phoneMap; The method of object assignment is copied and put into the method
private static void copyMap(Map<String, List<Phone>> sourceMap, Map<String, List<Phone>> targetMap) { targetMap = sourceMap; }
Then the problem arises. Xiao a debugs and finds that the copyMap(phoneMap, otherMap) has been executed; After that, otherMap is still empty. Then, ryuno suddenly saw the way, and then told him that method parameter passing in java is actually value passing. He also wrote an article before Discriminating value passing and reference passing in Java method parameters.
After reading this article, I believe you will understand the original, because Map has putAll() It copies all the elements of one Map to another, so change the method to the following
private static void copyMap(Map<String, List<Phone>> sourceMap, Map<String, List<Phone>> targetMap) { targetMap.putAll(sourceMap); }
If this article is helpful to you, please give "Lingye Jun" a praise. Thank you for your support.