ConcurrentHashMap JDK 8何时使用computeIfPresent

ver*_*tas 19 java concurrency multithreading concurrenthashmap

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

computeIfAbsent

computeIfPresent

putIfAbsent - 旧方法

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

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

Mar*_*o13 33

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

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

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

import java.util.LinkedHashMap;
import java.util.Map;

public class ComputeIfPresentExample 
{
    public static void main(String[] args) 
    {
        Map<String, Integer> wordCounts = new LinkedHashMap<String, Integer>();

        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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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


ste*_*fen 9

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

Map<String, Collection<String>> strings = new HashMap<>();
Run Code Online (Sandbox Code Playgroud)

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;
    });
}
Run Code Online (Sandbox Code Playgroud)

例:

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

这在多线程环境中非常强大,因为ConcurrentMaps可以自动执行这些操作。

删除操作可以是单行的:

void removeString(String a) {
    String index = a.substring(0, 1);
    strings.computeIfPresent(index, (i, c) -> c.remove(a) && c.isEmpty() ? null : c);
}
Run Code Online (Sandbox Code Playgroud)

  • 这是`computeIfPresent`的真实用例。 (2认同)