ConcurrentHashMap JDK 8何时使用computeIfPresent

jdk 8的新版Concurrent Hash Map有两个新方法。

computeIfAbsent

computeIfPresent

putIfAbsent – 旧方法

我理解putIfAbsentcomputeIfAbsent的用例。 但我不确定何时使用computeIfPresent 。 另外,如果我现在有computeIfPresent,为什么还需要putIfAbsent。 putIfAbsent会创建至少一个额外的值实例。

原因只是具有向后兼容性吗?

正如在另一个答案中所提到的:即使引入了新的,更强大的“方法”,也始终保留方法以实现向后兼容。

关于computeIfPresent的用例:可能很难找到一个足够小的例子,看起来不做作,但仍然令人信服。 通常,此方法的目的是以任何forms更新现有值。

一个示例可以是(约束的) 字数 :对于给定的一组字,一个在地图中存储初始计数0 。 然后,处理一系列单词:每当从初始集中找到一个单词时,其计数增加1:

 import java.util.LinkedHashMap; import java.util.Map; public class ComputeIfPresentExample { public static void main(String[] args) { Map wordCounts = new LinkedHashMap(); String s = "Lorem ipsum dolor sit amet consetetur iam nonumy sadipscing " + "elitr, sed diam nonumy eirmod tempor invidunt ut erat sed " + "labore et dolore magna dolor sit amet aliquyam erat sed diam"; wordCounts.put("sed", 0); wordCounts.put("erat", 0); for (String t : s.split(" ")) { wordCounts.computeIfPresent(t, (k,v) -> v+1); } System.out.println(wordCounts); } } 

(当然,这样的事情可以用不同的方式解决,但这是一种相当频繁的任务forms,新方法允许一个相当简洁和优雅的解决方案)

一个常见的用例是带有集合的 地图 ,例如

 Map> strings = new HashMap<>(); 

computeIfAbsentcomputeIfPresent是向集合添加元素或从集合中删除元素的非常方便的操作。 这是一个通过第一个字符串对字符串进行分组的示例。 请注意,必要时会创建键和集合,并在集合变空时将其清除:

 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; }); } 

这在multithreading环境中非常强大,因为ConcurrentMaps以primefaces方式执行这些操作。

例:

  // {} addString("a1"); // {a=[a1]} <-- collection dynamically created addString("a2"); // {a=[a1, a2]} removeString("a1"); // {a=[a2]} removeString("a2"); // {} <-- both key and collection removed 

一些额外的糖:

 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, (i, c) -> c.remove(a) && c.isEmpty() ? null : c); } 

JDK几乎没有打破向后兼容性。 因为那时您无法轻松地从具有最新版本的旧版本移植或运行软件。

您可以运行使用旧版本库编译的软件,其中包含仍具有这些function的任何版本(即安装了JRE的用户)。

我使用computeIfPresent作为一种从null安全的方式从字符串映射中获取小写值。

 String s = fields.computeIfPresent("foo", (k,v) -> v.toLowerCase()) 

在computeIfPresent可用之前,我必须这样做:

 String s = map.get("foo"); if (s != null) { s = s.toLowerCase(); } 

或这个:

 String s = map.containsKey("foo") ? map.get("foo").toLowerCase() : null;