HashMap使用java 8流API的平均计数?

bra*_*orm 1 dictionary java-8 java-stream

我有Map以下类型

public class MapUtils {

    private Map<String, Integer> queryCounts = new HashMap<>();

public void averageCounters(){

    int totalCounts = queryCounts.values().stream().reduce(0, Integer::sum);
    queryCounts = queryCounts.entrySet()
                             .stream()
                             .collect(Collectors.toMap(
                                 Map.Entry::getKey,
                                 (Map.Entry::getValue)/totalCounts
    ));
}
Run Code Online (Sandbox Code Playgroud)

这不会编译并在此行中显示错误(Map.Entry::getValue)/totalCounts.我该如何解决?有没有更好的方法来获得Map使用Java 8 API的平均值?

编辑:这是一个更好的方法吗?

queryCounts.entrySet()
           .forEach(entry -> queryCounts.put(entry.getKey(),
                                   entry.getValue()/totalCounts));
Run Code Online (Sandbox Code Playgroud)

Tag*_*eev 9

如果您想要就地修改,那么使用Map.replaceAll而不是Stream API 会更好:

int totalCounts = queryCounts.values().stream()
                             .collect(Collectors.summingInt(Integer::intValue));
queryCounts.replaceAll((k, v) -> v/totalCounts);
Run Code Online (Sandbox Code Playgroud)

但是在您的情况下,此解决方案存在问题,因为除法结果将四舍五入为int数字,因此您几乎总是会在结果中得到零.实际上你的代码中存在同样的问题.您可能希望将其Map<String, Double>作为结果类型.所以你可能需要创建一个全新的Map:

Map<String, Double> averages = queryCounts.entrySet().stream()
                                          .collect(Collectors.toMap(Entry::getKey,
                                              e -> ((double)e.getValue())/totalCounts));
Run Code Online (Sandbox Code Playgroud)

另一种方法是首先queryCounts声明Map<String, Double>.这样你就可以使用replaceAll:

double totalCounts = queryCounts.values().stream()
                             .collect(Collectors.summingDouble(Double::doubleValue));
queryCounts.replaceAll((k, v) -> v/totalCounts);
Run Code Online (Sandbox Code Playgroud)

最后还有一个替代方案,它是最有效的,但很脏.您的代码假定调用queryCounts后不需要原始(非平均)averageCounters().因此,您可以保持queryCountsas Map<String, Integer>(这比计数更有效Map<String, Double>),但然后更改Map值类型如下:

double totalCounts = queryCounts.values().stream()
                             .collect(Collectors.summingInt(Integer::intValue));
Map<String, Object> map = (Map<String, Object>)queryCounts;
map.replaceAll((k, v) -> ((Integer)v)/totalCounts);
Map<String, Double> averages = (Map<String, Double>)map;
queryCounts = null;
Run Code Online (Sandbox Code Playgroud)

在实现中的JDK中执行类似的技巧Collectors.groupingBy.