Java8
对于Map
新增了 几个非常有用的API
,这里我着重强调下如下 2 个:
computeIfPresent
:当key 映射的value 存在的时候,如何处理 valuecomputeIfAbsent
:当 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
这个让我工作中的代码变得异常简洁了,非常推荐。