一个常见的用例是带有集合的地图,例如
Map<String, Collection<String>> strings = new HashMap<>();
computeIfAbsent
和 computeIfPresent
是非常方便的操作,用于在集合中添加和删除元素。尤其是因为与 不同,这些方法返回当前值(无论它是否刚刚创建)。下面是一个按字符串的第一个字符对字符串进行分组的示例。请注意,密钥和集合都是在必要时创建的,并在集合变为空时进行清理:put()
compute*()
void addString(String a) {
String index = a.substring(0, 1);
strings.computeIfAbsent(index, ign -> new HashSet<>()).add(a);
}
void removeString(String a) {
String index = a.substring(0, 1);
strings.computeIfPresent(index, (k, c) -> {
c.remove(a);
return c.isEmpty() ? null : c;
});
}
例:
// {}
addString("a1"); // {a=[a1]} <-- collection dynamically created
addString("a2"); // {a=[a1, a2]}
removeString("a1"); // {a=[a2]}
removeString("a2"); // {} <-- both key and collection removed
这在多线程环境中非常强大,因为 ConcurrentMap 以
原子方式执行这些操作。
删除操作可以是单行操作:
void removeString(String a) {
String index = a.substring(0, 1);
strings.computeIfPresent(index, (i, c) -> c.remove(a) && c.isEmpty() ? null : c);
}
所以再一次简而言之:
Map<String, Set<String>> map = new ConcurrentHashMap<>();
map.computeIfAbsent(key, i -> ConcurrentHashMap.newKeySet()).add(value);
map.computeIfPresent(key, (i, s) -> s.remove(value) && s.isEmpty() ? null : s);