Если вы хотите в месте изменения, это гораздо лучше использовать Map.replaceAll
вместо потока API:
int totalCounts = queryCounts.values().stream()
.collect(Collectors.summingInt(Integer::intValue));
queryCounts.replaceAll((k, v) -> v/totalCounts);
Однако в вашем случае это решение является проблематичным, так как результаты деления будут округлены до int
число, таким образом, вы почти всегда получите нули в результате. На самом деле в коде есть одна и та же проблема. Вероятно, вы хотите получить Map<String, Double>
в качестве результата. Таким образом, вы, вероятно, нужно, чтобы создать совершенно новый Map
:
Map<String, Double> averages = queryCounts.entrySet().stream()
.collect(Collectors.toMap(Entry::getKey,
e -> ((double)e.getValue())/totalCounts));
Альтернативой будет иметь queryCounts
объявлен Map<String, Double>
в первую очередь. Таким образом, вы можете использовать replaceAll
:
double totalCounts = queryCounts.values().stream()
.collect(Collectors.summingDouble(Double::doubleValue));
queryCounts.replaceAll((k, v) -> v/totalCounts);
Наконец, есть еще одна альтернатива, которая является наиболее эффективным, но грязный. Ваш код предполагает, что оригинальные (не усредненные) queryCounts
не нужны после вызова averageCounters()
. Таким образом, вы можете сохранить queryCounts
в 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;
Подобный трюк в JDK performed внутри Collectors.groupingBy
реализации.