ConcurrentHashMap JDK 8何时使用computeIfPresent
jdk 8的新版Concurrent Hash Map有两个新方法。
computeIfAbsent
computeIfPresent
putIfAbsent – 旧方法
我理解putIfAbsent和computeIfAbsent的用例。 但我不确定何时使用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<>();
computeIfAbsent
和computeIfPresent
是向集合添加元素或从集合中删除元素的非常方便的操作。 这是一个通过第一个字符串对字符串进行分组的示例。 请注意,必要时会创建键和集合,并在集合变空时将其清除:
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;
- 完成所有ExecutorService任务后,程序不会立即终止
- Java并发:“级联”变量中的易失性与最终性?
- ExecutorService的shutdown()不会等到所有线程都完成
- Singleton实现中的Initialize-On-Demand习语与简单的静态初始化程序
- 用于java.util.concurrent.Future的scala.concurrent.Future包装器
- 如何使Spring JMSListener突发到最大并发线程?
- 从ScheduledExecutorService中运行的任务本身中停止定期任务
- 为什么我要在并行流中使用并发特性和collect?
- 同步块可以比Atomics更快吗?