驽马十驾 驽马十驾

驽马十驾,功在不舍

目录
Java8新增的 Map相关 API:computeIfPresent 和 computeIfAbsent
/      

Java8新增的 Map相关 API:computeIfPresent 和 computeIfAbsent

开篇

Java8对于Map新增了 几个非常有用的API,这里我着重强调下如下 2 个:

  • computeIfPresent:当key 映射的value 存在的时候,如何处理 value
  • computeIfAbsent:当 key 映射的 value 存在的时候,如何生成 value

分别对应的是 key 对应的 value 存在或者不存在时候的逻辑,用的好可以减少代码行数,逻辑表述更清晰。

典型场景

在一个 key 对应的value 是一个multieValue的场景下(比如 Map<String,Set<String>>),添加或者删除对应的元素,就可以很方便的使用上述 2 个方法了

我们还是通过代码来理解一下吧。

新增元素

对于Map<String,Set<String>>,在没有computeIfAbsent的时候,我们可以这么写。

    private Map<String, Set<String>> put(String key, String value, Map<String, Set<String>> map) {
        Set<String> set = map.get(key);
        if (set == null) {
            set = new HashSet<>();
            map.put(key, set);
        }
        set.add(value);
        return map;
    }

但是可以利用computeIfAbsent大大的简化代码,如下所示:

map.computeIfAbsent("a", k -> new HashSet<>()).add("1");

其中k->new HashSet<>() 表示在key值为a的时候,没有映射 value的时候,new一个HashSet并将其与 key进行映射,类似代码:

        if (set == null) {
            set = new HashSet<>();
            map.put(key, set);
        }

删除元素

同样的,我们对一个multivalueSet删除某个元素的时候,假如使用传统写法,可能是这样的

    private Map<String, Set<String>> remove(String key, String value, Map<String, Set<String>> map) {
        Set<String> set = map.get(key);
        if (set == null) {
            return map;
        }
        set.remove(value);
        return map;
    }

但是假如我们如果利用computeIfPresent,那么可以这么写:

        map.computeIfPresent("a", (k, set) -> {
            set.remove("2");
            return set;
        });

这样看上去的代码是不是很简洁了。

并发场景

那么假如是在并发场景下,如果要自己写,你可能会的会存在些许问题,不过当你利用ConcurrentHashMap这线程安全的集合作为上层控制,利用线程安全的 Set,比如ConcurrentSet这样线程安全的 value来做multiValue的容器,那么基本上就没有什么大问题了。

JDK 没有原生提供ConcurrentSet,不过假如你了解Set的可以通过HashMap来实现的时候,你就可以实现了,具体的实现可以参考该地址:参考实现

我们先来看看并发场景下的使用

        //新增
	Map<String, ConcurrentHashSet<String>> map = new ConcurrentHashMap<>();
        map.computeIfAbsent("a", k -> new ConcurrentHashSet<>()).add("1");
			 //删除
        map.computeIfPresent("a", (k, o) -> {
            o.remove("2");
            return o;
        });
  • 新增的时候,仅仅是构建multiValue的时候,更改为线程安全的ConcurrentHashSet即可。
  • 删除的时候,没有区别。

结语

上述 2 个 API,个人觉得最有用的还是computeIfAbsent这个让我工作中的代码变得异常简洁了,非常推荐。

不积跬步,无以至千里。不积小流,无以成江海。