jdk 8的新版Concurrent Hash Map有两个新方法。
computeIfAbsent
computeIfPresent
putIfAbsent - 旧方法
我了解 putIfAbsent 和 computeIfAbsent 的用例。 但我不确定我将使用 computeIfPresent 的情况。 另外,如果我现在有computeIfPresent,为什么还需要putIfAbsent。 putIfAbsent会创建至少一个额外的值实例。
原因只是具有向后兼容性吗?
答案 0 :(得分:31)
正如在另一个答案中所提到的:即使引入了新的,更强大的“方法”,也始终保留方法以实现向后兼容。
关于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);
}
}
(当然,这样的事情可以用不同的方式解决,但这是一种相当频繁的任务形式,新方法允许一个相当简洁和优雅的解决方案)
答案 1 :(得分:5)
一个常见的用例是maps和collections,例如
Map<String, Collection<String>> 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;
});
}
示例:
// {}
addString("a1"); // {a=[a1]} <-- collection dynamically created
addString("a2"); // {a=[a1, a2]}
removeString("a1"); // {a=[a2]}
removeString("a2"); // {} <-- both key and collection removed
这在多线程环境中非常强大,因为ConcurrentMaps
以原子方式执行这些操作。
删除操作可以是一行代码:
void removeString(String a) {
String index = a.substring(0, 1);
strings.computeIfPresent(index, (i, c) -> c.remove(a) && c.isEmpty() ? null : c);
}
答案 2 :(得分:0)
JDK几乎没有打破向后兼容性。因为那时您无法轻松地从具有最新版本的旧版本移植或运行软件。
您可以运行使用旧版本库编译的软件,其中包含仍具有这些功能的任何版本(即安装了JRE的用户)。
答案 3 :(得分:-1)
我使用computeIfPresent作为从字符串映射中获取小写值的空安全方法。
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;