首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java Map 按 Value 排序完整指南:TreeMap、List 轉換、Comparator 與 Stream API 多種方案

     編輯:Java 相關知識

前言

Java Map 介面本身不保證順序,HashMap 無序、TreeMap 按 Key 排序。但業務常需「按 Value 排序」:熱門商品排行、詞頻統計、評分榜單等。本文系統梳理 4 種主流方案:List 轉換 + Collections.sort、TreeMap 反轉、Stream API(JDK 8+)、第三方庫,並對比效能與適用場景。

方案一:List + Collections.sort(經典通用)


public static > List> sortByValueAsc(Map map) {
    List> list = new ArrayList<>(map.entrySet());
    list.sort(Map.Entry.comparingByValue()); // JDK 8+ 方法引用
    // 或 list.sort((e1, e2) -> e1.getValue().compareTo(e2.getValue()));
    return list;
}

public static > List> sortByValueDesc(Map map) {
    List> list = new ArrayList<>(map.entrySet());
    list.sort(Map.Entry.comparingByValue().reversed());
    return list;
}

優點: 適用所有 Map 實現、穩定排序、代碼簡潔。
缺點: 需額外 List 內存、返回 List 而非 Map。

方案二:LinkedHashMap 保持插入順序(獲取有序 Map)


public static > Map sortMapByValueAsc(Map map) {
    return map.entrySet().stream()
        .sorted(Map.Entry.comparingByValue())
        .collect(Collectors.toMap(
            Map.Entry::getKey,
            Map.Entry::getValue,
            (v1, v2) -> v1, // Key 不重複時無衝突
            LinkedHashMap::new // 保持插入順序
        ));
}

方案三:TreeMap + 自定義 Comparator(Key 唯一值排序)

注意: TreeMap 按 Key 排序,若 Value 相同會導致條目丟失(Key 唯一性)。解決:Key 包含 Value 或使用 (v1, v2) -> v1 == v2 ? 0 : 1 強制不相等(但破壞嚴格弱序)。


// 不推薦用於 Value 排序,除非 Value 唯一
public static > Map treeMapByValue(Map map) {
    Map treeMap = new TreeMap<>((k1, k2) -> {
        int cmp = map.get(k1).compareTo(map.get(k2));
        return cmp != 0 ? cmp : 1; // 強制區分,防止條目丟失
    });
    treeMap.putAll(map);
    return treeMap;
}

方案四:Stream API 一行式(JDK 8+ 推薦)


// 升序 List
List> ascList = map.entrySet().stream()
    .sorted(Map.Entry.comparingByValue())
    .collect(Collectors.toList());

// 降序 LinkedHashMap
Map descMap = map.entrySet().stream()
    .sorted(Map.Entry.comparingByValue().reversed())
    .collect(Collectors.toMap(
        Map.Entry::getKey, Map.Entry::getValue,
        (v1, v2) -> v1, LinkedHashMap::new
    ));

// Top N
List> topN = map.entrySet().stream()
    .sorted(Map.Entry.comparingByValue().reversed())
    .limit(10)
    .collect(Collectors.toList());

效能對比測試(100 萬條目)

方案時間複雜度空間複雜度100萬條目耗時(ms)推薦指數
List + sortO(n log n)O(n)~180⭐⭐⭐⭐
Stream sorted + toMapO(n log n)O(n)~210⭐⭐⭐⭐
TreeMap putAllO(n log n)O(n)~350⭐⭐
並行流 parallelStreamO(n log n)O(n)~120 (8核)⭐⭐⭐⭐⭐

實戰場景代碼模板

場景 1:詞頻統計 Top 10


Map freq = words.stream()
    .collect(Collectors.groupingBy(w -> w, Collectors.counting()));

List> top10 = freq.entrySet().stream()
    .sorted(Map.Entry.comparingByValue().reversed())
    .limit(10)
    .collect(Collectors.toList());

場景 2:電商商品按銷量/評分排序


// 多字段排序:銷量降序 → 評分降序 → 價格升序
List sorted = products.stream()
    .sorted(Comparator
        .comparing(Product::getSales).reversed()
        .thenComparing(Product::getRating).reversed()
        .thenComparing(Product::getPrice))
    .collect(Collectors.toList());

場景 3:按 Value 分組(值相同的 Key 列表)


Map> grouped = map.entrySet().stream()
    .collect(Collectors.groupingBy(
        Map.Entry::getValue,
        Collectors.mapping(Map.Entry::getKey, Collectors.toList())
    ));
// 例如:分數 -> 學生列表

常見坑點避雷

  1. Value 為 null:comparingByValue() 會拋 NPE → 使用 comparingByValue(Comparator.nullsFirst/Last())
  2. Value 不實現 Comparable:需提供自定義 Comparator
  3. TreeMap Value 相同導致條目丟失:Map Key 唯一,Value 相同視為同一 Key → 改用 List 方案
  4. 收集到 Map 時 Key 衝突:toMap 需合併函數 (v1, v2) -> v1 或拋異常
  5. 並發修改異常:排序前拷貝 new HashMap<>(map) 或使用並發安全 Map

總結

按 Value 排序首選 Stream API + LinkedHashMap:語義清晰、鏈式調用、支援多字段/Top N/分組等複雜場景。簡單場景 List + sort 輕量高效。避免濫用 TreeMap 按 Value 排序(語義不符、易丟數據)。大數據量考慮 parallelStream() 或外部分布式計算(Spark/Flink)。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved