踩坑记-Map.getOrDefault(Object key, V defaultValue)

1,452 阅读2分钟

问题重现

在一个项目中需要根据key进行分组,使用了Map<String, List>的结构,如下代码:

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.collections4.CollectionUtils;

import java.util.List;
import java.util.Map;

public class MapTest {
    public static void main(String[] args) {
        Map<String, List<String>> map = group(Lists.newArrayList("Hello", "Hello", "World", "Java", "PHP"));
        System.out.println(map);
    }

    public static Map<String, List<String>> group(List<String> listStr) {
        if (CollectionUtils.isEmpty(listStr)) {
            return Maps.newHashMap();
        }

        Map<String, List<String>> map = Maps.newHashMap();
        listStr.forEach(e -> map.getOrDefault(e, Lists.newLinkedList()).add(e));
        return map;
    }
}

输出

{}

分析原因

经过运行后,发现并没有按照预期进行分组,反而分组后的map是{},在项目中debug运行多次发现仍旧是空的,后来觉得问题应该是出在了 getOrDefault 上,初看这代码感觉没有什么问题啊,并且查看了源码,源码如下:

default V getOrDefault(Object key, V defaultValue) {
    V v;
    return (((v = get(key)) != null) || containsKey(key))
        ? v
        : defaultValue;
}

当key不存在的时候,返回默认的值,对于本次代码也是有默认值——Lists.newLinkedList(),返回了默认值 list,通过add()方法添加元素,也是没有问题的啊!况且,返回的是 LinkedList 的引用!

仔细一想,恍然大悟,终于明白了其中的原因!返回的默认 LinkedList 肯定也是添加上了值!没有返回的原因是,这个LinkedList的引用并没有跟Map建立真正的关系,它处于一种游离状态,方法运行完成就销毁了!代码修改一下,验证一下 LinkedList 添加了元素。

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.collections4.CollectionUtils;

import java.util.List;
import java.util.Map;

public class MapTest {
    public static void main(String[] args) {
        Map<String, List<String>> map = group(Lists.newArrayList("Hello", "Hello", "World", "Java", "PHP"));
        System.out.println(map);
    }

    public static Map<String, List<String>> group(List<String> listStr) {
        if (CollectionUtils.isEmpty(listStr)) {
            return Maps.newHashMap();
        }

        Map<String, List<String>> map = Maps.newHashMap();
        listStr.forEach(e -> {
            List<String> list = Lists.newLinkedList();
            map.getOrDefault(e, list).add(e);
            System.out.println(list);
        });
        return map;
    }
}

输出

[Hello]
[Hello]
[World]
[Java]
[PHP]
{}

图示

问题已经知道了,修改就简单了~