你可以通过概括过程来解决这个问题:
private static <K,V,R> Map<K,R>
replaceAndSortValues(Map<K,V> m, Function<V,R> f, Comparator<R> c) {
return m.entrySet().stream()
.map(e -> Map.entry(e.getKey(), f.apply(e.getValue())))
.sorted(Map.Entry.comparingByValue(c.reversed()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
(a,b) -> { throw new AssertionError(); },
LinkedHashMap::new));
}
此方法使用与指定映射相同的键创建新映射,使用指定函数替换所有值,并根据指定比较器的反转对条目进行排序。它使用java9s
Map.entry(â¦, â¦)
工厂。如果必须支持java8或
null
键或值,可以使用
new AbstractMap.SimpleImmutableEntry<>(â¦, â¦)
相反。
现在可以使用此方法替换内部映射
List
带着
Integer
s表示其大小并按降序排序,并将替换操作用作外部映射的替换函数:
public static Map<String, Map<String, Integer>>
getCallWithStateSizeGroup(ThreadDumpDo threadDumpDo) {
return replaceAndSortValues(getCallStackWithStateGroup(threadDumpDo),
m -> replaceAndSortValues(m, List::size, Comparator.<Integer>naturalOrder()),
Comparator.comparing(m -> m.values().iterator().next()));
}
这与你发布的解决方案基本相同。外部映射比较器使用新的内部映射已经排序的事实,因此它们的第一个值是最大值。但里面一定没有空地图。
这很容易适应,以保持
List<ThreadDo>
按大小分类:
public static Map<String, Map<String, List<ThreadDo>>>
getCallWithStateSizeGroup(ThreadDumpDo threadDumpDo) {
return replaceAndSortValues(getCallStackWithStateGroup(threadDumpDo),
m -> replaceAndSortValues(m, Function.identity(),
Comparator.comparingInt(List::size)),
Comparator.comparingInt(m -> m.values().iterator().next().size()));
}
我们只需要将内部映射替换函数更改为
Function.identity()
并提供一个使用列表大小的比较器。外部映射的比较器仍然可以使用这样一个事实,即内部映射此时已经排序,但是还必须提取
size()
以供比较。