如何将按Type分组的Map<Type,List<String>>按值排序存入LinkedHashMap
解决Map按List值排序的编译错误
问题背景
定义了如下Item类和菜单列表:
@AllArgsConstructor @Getter public static class Item { public enum Type { Meat, Fish } private String name; private int price; private Type type; }
List<Item> menu = Arrays.asList( new Item("pork", 800, Item.Type.Meat), new Item("beef", 700, Item.Type.Meat), new Item("chicken", 200, Item.Type.Meat), new Item("prawns", 300, Item.Type.Fish), new Item("salmon", 450, Item.Type.Fish) );
需求是将Item按Type分组存入Map,再将该Map的条目按值(List<String>类型)升序排序后存入LinkedHashMap,但尝试的代码出现编译错误:
Type parameter 'java.util.List' is not within its bound; should extend 'java.lang.Comparable<? super java.util.List>'
错误原因
Map.Entry.comparingByValue()默认要求值类型实现Comparable接口,而List<String>并没有实现该接口(虽然String是Comparable,但容器本身不是),所以无法直接使用默认的比较方法。
解决方案
需要为List<String>自定义比较逻辑,以下是两种常见实现方式:
方式1:按List的元素数量排序
如果需求是按分组后列表的大小升序排序,可直接基于列表长度构建比较器:
// 按Type分组 Map<Item.Type, List<String>> map = menu.stream() .collect(Collectors.groupingBy( Item::getType, Collectors.mapping(Item::getName, Collectors.toList()) )); // 按List大小升序排序并存入LinkedHashMap Map<Item.Type, List<String>> sortedMap = map.entrySet().stream() .sorted(Map.Entry.comparingByValue(Comparator.comparingInt(List::size))) .collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (oldVal, newVal) -> oldVal, LinkedHashMap::new ));
方式2:按List中元素的字典序排序
如果需要按列表内元素的自然顺序(字典序)逐个比较排序,可自定义列表比较逻辑:
// 按Type分组 Map<Item.Type, List<String>> map = menu.stream() .collect(Collectors.groupingBy( Item::getType, Collectors.mapping(Item::getName, Collectors.toList()) )); // 自定义List<String>比较器:逐个元素比较,长度短的在前 Comparator<List<String>> listComparator = (list1, list2) -> { int minSize = Math.min(list1.size(), list2.size()); for (int i = 0; i < minSize; i++) { int cmp = list1.get(i).compareTo(list2.get(i)); if (cmp != 0) { return cmp; } } return Integer.compare(list1.size(), list2.size()); }; // 按自定义逻辑排序并存入LinkedHashMap Map<Item.Type, List<String>> sortedMap = map.entrySet().stream() .sorted(Map.Entry.comparingByValue(listComparator)) .collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (oldVal, newVal) -> oldVal, LinkedHashMap::new ));
优化点说明
- 直接使用
Collectors.toMap()结合LinkedHashMap构造器,替代手动创建LinkedHashMap再forEachOrdered的方式,代码更简洁且符合流式编程习惯。 - 自定义比较器时,需明确排序规则(长度、元素顺序等),根据实际业务需求选择合适的逻辑。
内容的提问来源于stack exchange,提问作者Mark Skylarkxx
相关产品推荐
相关产品推荐

