如何根据自定义类的String成员变量对HashMap进行排序
问题描述
我有一个类型为Map<Integer, CustomClass>的HashMap,CustomClass定义如下:
class CustomClass { String s; Integer i; // 构造方法、getter和setter }
已完成Map的初始化并填充数据:
Map<Integer, CustomClass> map = new HashMap<>();
我需要根据CustomClass的String类型成员s对这个HashMap排序,尝试用Lambda表达式没得到正确的有序Map,还写了以下模拟代码:
import java.util.*; class FileMap implements Comparable<FileMap> { private String fileName; private int file; public FileMap(String fileName, int file) { this.fileName = fileName; this.file = file; } public String getFileName() { return fileName; } public void setFileName(String fileName) { this.fileName = fileName; } public int getFile() { return file; } public void setFile(int file) { this.file = file; } @Override public int compareTo(FileMap that) { return this.fileName.compareTo(that.getFileName()); } @Override public String toString() { return this.fileName; } } class Main { public static void main(String[] args) { FileMap fm1 = new FileMap("abc.txt", 0); FileMap fm2 = new FileMap("abd.txt", 0); FileMap fm3 = new FileMap("abe.txt", 0); FileMap fm4 = new FileMap("abf.txt", 0); Map<Integer, FileMap> fileMap = new HashMap<>(); fileMap.put(0, fm1); fileMap.put(1, fm3); fileMap.put(2, fm2); fileMap.put(3, fm4); System.out.println(fileMap); Map<Integer, FileMap> tree = new TreeMap<>(); tree.putAll(fileMap); System.out.println(tree); } }
但问题仍未解决,求正确实现方法。
解决方案
你当前代码的核心问题:TreeMap默认是按**键(Key)**排序的,和值的Comparable实现完全无关。你的键是Integer类型,所以TreeMap只会按整数顺序输出,自然达不到按fileName排序的目的。
下面是两种可行的实现方式:
方法1:将Entry转为List后排序,再存入有序Map
把HashMap的键值对提取到List,用自定义规则排序后,存入LinkedHashMap保持顺序:
// 提取所有键值对到List List<Map.Entry<Integer, CustomClass>> entryList = new ArrayList<>(map.entrySet()); // 按CustomClass的s字段升序排序 entryList.sort((entry1, entry2) -> { String s1 = entry1.getValue().getS(); String s2 = entry2.getValue().getS(); return s1.compareTo(s2); // 降序则改为s2.compareTo(s1) }); // 存入LinkedHashMap保留排序结果 Map<Integer, CustomClass> sortedMap = new LinkedHashMap<>(); for (Map.Entry<Integer, CustomClass> entry : entryList) { sortedMap.put(entry.getKey(), entry.getValue()); } // 验证输出 sortedMap.forEach((k, v) -> System.out.println(k + ": " + v.getS()));
对应你的模拟代码,修改Main方法如下:
public static void main(String[] args) { FileMap fm1 = new FileMap("abc.txt", 0); FileMap fm2 = new FileMap("abd.txt", 0); FileMap fm3 = new FileMap("abe.txt", 0); FileMap fm4 = new FileMap("abf.txt", 0); Map<Integer, FileMap> fileMap = new HashMap<>(); fileMap.put(0, fm1); fileMap.put(1, fm3); fileMap.put(2, fm2); fileMap.put(3, fm4); System.out.println("原HashMap:" + fileMap); // 排序逻辑 List<Map.Entry<Integer, FileMap>> entryList = new ArrayList<>(fileMap.entrySet()); entryList.sort((e1, e2) -> e1.getValue().getFileName().compareTo(e2.getValue().getFileName())); Map<Integer, FileMap> sortedMap = new LinkedHashMap<>(); entryList.forEach(entry -> sortedMap.put(entry.getKey(), entry.getValue())); System.out.println("按fileName排序后的Map:" + sortedMap); }
方法2:用Stream API简化操作
Java 8+的Stream可以更简洁地完成排序和收集:
Map<Integer, CustomClass> sortedMap = map.entrySet() .stream() .sorted(Map.Entry.comparingByValue((v1, v2) -> v1.getS().compareTo(v2.getS()))) .collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (oldVal, newVal) -> oldVal, // 键冲突时保留旧值 LinkedHashMap::new // 指定用LinkedHashMap保持顺序 ));
对应模拟代码的Stream版本:
Map<Integer, FileMap> sortedMap = fileMap.entrySet() .stream() .sorted(Map.Entry.comparingByValue(Comparator.comparing(FileMap::getFileName))) .collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (o, n) -> o, LinkedHashMap::new ));
注意事项
- 不要试图用
TreeMap实现按值排序,它的核心逻辑是按键排序,强行修改会导致键的比较逻辑混乱,甚至出现键覆盖问题。 - 如果
CustomClass的s字段可能为null,要在Comparator中处理空指针,比如:entryList.sort((e1, e2) -> { String s1 = e1.getValue().getS(); String s2 = e2.getValue().getS(); if (s1 == null) return s2 == null ? 0 : -1; if (s2 == null) return 1; return s1.compareTo(s2); });
内容的提问来源于stack exchange,提问作者Bhupesh Patil
相关产品推荐
相关产品推荐

