重构if-else块以使用Map.computeIfAbsentMap.computeIf返回错误的结果



我有一个类

public class Gezana {
private String name;
private long value;
}

和一个类似的列表:

List<Gezana> list = List.of(new Gezana("foo", 2), 
new Gezana("foo", 2),
new Gezana("foo", 2),
new Gezana("foo", 2), 
new Gezana("bar", 5),
new Gezana("bar", 5), 
new Gezana("bar", 5), 
new Gezana("doo", 9), 
new Gezana("doo", 9),
new Gezana("kee", 12));

我需要使用上面的列表创建一个映射,名称作为关键字,值的总和作为值。我曾经用以下方式来做:

Map<String, Long> oldMap = new HashMap<>(); 
for (Gezana gez : list) {            
if (oldMap.containsKey(gez.getName())) {
oldMap.put(gez.getName(), oldMap.get(gez.getName()) + gez.getValue());
} else{
oldMap.put(gez.getName(), gez.getValue());
}          
}        
System.out.println("old map:" + oldMap);

我需要重构上面的内容,并考虑使用Map.computeIfAbsent & Map.computeIfPresent,但没有得到预期的结果

Map<String, Long> map = new HashMap<>(); 
for (Gezana gez : list) {            
map.computeIfAbsent(gez.getName(), k -> gez.getValue());     
map.computeIfPresent(gez.getName(), (k, v)->  v + gez.getValue());              
}
System.out.println("new map:" + map);

输出:

old map:{bar=15, doo=18, foo=8, kee=12}
new map:{bar=20, doo=27, foo=10, kee=24}

似乎新映射为添加的每个键都有一个附加值,但我没有看到使用computeOfAbsent&computeInfoPresent方法。有什么提示吗?

这个问题是computeIfAbsent总是添加到映射中;CCD_ 3随后将更新CCD_ 4可能刚刚添加的内容。

因此,当第一次遇到一个名称时,它的值会被添加两次——一次是computeIfAbsent,然后是computeIfPresent

你可以用computeIfAbsent/computeIfPresent这样做:

map.computeIfAbsent(gez.getName(), k -> 0L);     
map.computeIfPresent(gez.getName(), (k, v)->  v + gez.getValue());

compute:

map.compute(gez.getName(), (k, v) -> (v != null ? v : 0L) + get.getValue());

但合并会更容易:

oldMap.merge(gez.getName(), gez.getValue(), Long::sum);

或者,直接从列表中选择:

Map<String, Long> map = 
list.stream().collect(groupingBy(Gezana::getName, summingLong(Gezana::getValue)))

最好应用Map::merge函数:

Map<String, Long> oldMap = new HashMap<>();
for (Gezana gez : list) {
oldMap.merge(gez.getName(), gez.getValue(), Long::sum);
}
System.out.println("old map:" + oldMap);

或使用流APICollectors.groupingByCollectors.summingLong:

Map<String, Long> newMap = list.stream()
.collect(Collectors.groupingBy(
Gezana::getName, 
Collectors.summingLong(Gezana::getValue)
));
System.out.println("new map:" + newMap);

输出:

old map:{bar=15, doo=18, foo=8, kee=12}
new map:{bar=15, doo=18, foo=8, kee=12}

最新更新