重构 if-else 块以使用 Map.computeIfAbsent Map.computeIfPresent 错误结果

nop*_*ens 2 java

我有课

public class Gezana {
    private String name;
    private long value;
}
Run Code Online (Sandbox Code Playgroud)

和一个类似的列表:

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

我需要使用上面的列表创建一个地图,其中名称作为键,值的总和作为值。我曾经通过以下方式做到这一点:

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

我需要重构上面的内容并考虑使用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);
Run Code Online (Sandbox Code Playgroud)

输出:

old map:{bar=15, doo=18, foo=8, kee=12}
new map:{bar=20, doo=27, foo=10, kee=24}
Run Code Online (Sandbox Code Playgroud)

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

And*_*ner 8

这样做的问题是computeIfAbsent总是会添加到地图中;computeIfPresent然后将更新可能刚刚添加的内容computeIfAbsent

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

computeIfAbsent/computeIfPresent你可以这样做:

map.computeIfAbsent(gez.getName(), k -> 0L);     
map.computeIfPresent(gez.getName(), (k, v)->  v + gez.getValue());
Run Code Online (Sandbox Code Playgroud)

或者compute

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

但合并会更容易:

oldMap.merge(gez.getName(), gez.getValue(), Long::sum);
Run Code Online (Sandbox Code Playgroud)

或者,直接从列表中:

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