Java Map排序如何按照值按照鍵排序
結(jié)論:只有 TreeMap 天生支持按鍵排序,HashMap/LinkedHashMap 需手動(dòng)處理,按值排序所有 Map 都要額外實(shí)現(xiàn)

一、先理清 3 種 Map 的默認(rèn)排序行為
| Map 類型 | 底層結(jié)構(gòu) | 默認(rèn)排序規(guī)則 | 核心特點(diǎn) |
|---|---|---|---|
| HashMap | 哈希表 | 無固定順序(隨機(jī)) | 查找快、無序、線程不安全 |
| TreeMap | 紅黑樹 | 按「鍵」自然排序(默認(rèn)升序) | 有序(鍵)、查找效率中等、可自定義排序 |
| LinkedHashMap | 哈希表 + 鏈表 | 按「插入順序」排序 | 有序(插入順序)、查找快、保留插入順序 |
簡單說:
- 想默認(rèn)按鍵有序 → 直接用 TreeMap;
- 想保留插入順序 → 用 LinkedHashMap;
- 只想要查詢快、不關(guān)心順序 → 用 HashMap;
- 按值排序 → 任何 Map 都要手動(dòng)處理(因?yàn)?Map 本質(zhì)是「鍵值對(duì)映射」,值不具備天然排序索引)。
二、按「鍵」排序的實(shí)現(xiàn)方式
按鍵排序的核心是:鍵必須是可比較的(實(shí)現(xiàn) Comparable 接口,如 String、Integer、Long 等),如果是自定義對(duì)象作為鍵,需手動(dòng)指定比較規(guī)則。
1. 方式 1:用 TreeMap (默認(rèn)按鍵升序,無需額外代碼)
TreeMap 天生支持按鍵排序,默認(rèn)是「自然升序」(比如數(shù)字從小到大、字符串按字典序)。
import java.util.TreeMap;
public class MapSortByKey {
public static void main(String[] args) {
// 1. TreeMap 默認(rèn)按鍵自然升序排序(鍵是 Integer 類型,可比較)
TreeMap<Integer, String> treeMap = new TreeMap<>();
treeMap.put(3, "蘋果");
treeMap.put(1, "香蕉");
treeMap.put(2, "橘子");
System.out.println("TreeMap 默認(rèn)按鍵升序:" + treeMap);
// 輸出:{1=香蕉, 2=橘子, 3=蘋果}(按鍵 1→2→3 排序)
}
}2. 方式 2:TreeMap 自定義鍵排序(比如降序、自定義對(duì)象鍵)
如果想按鍵降序,或鍵是自定義對(duì)象(比如 User),需要傳入 Comparator 接口指定排序規(guī)則。
示例 2.1:TreeMap 按鍵降序
import java.util.Comparator;
import java.util.TreeMap;
public class MapSortByKeyDesc {
public static void main(String[] args) {
// 傳入 Comparator.reverseOrder() 實(shí)現(xiàn)鍵降序
TreeMap<Integer, String> treeMapDesc = new TreeMap<>(Comparator.reverseOrder());
treeMapDesc.put(3, "蘋果");
treeMapDesc.put(1, "香蕉");
treeMapDesc.put(2, "橘子");
System.out.println("TreeMap 按鍵降序:" + treeMapDesc);
// 輸出:{3=蘋果, 2=橘子, 1=香蕉}(按鍵 3→2→1 排序)
}
}示例 2.2:自定義對(duì)象作為 TreeMap 的鍵(需指定比較規(guī)則)
比如用 User 對(duì)象作為鍵,按 userId 升序排序:
import java.util.Comparator;
import java.util.TreeMap;
// 自定義 User 類(作為鍵)
class User {
private int userId;
private String name;
// 構(gòu)造方法、getter、toString(必須重寫,否則打印亂碼)
public User(int userId, String name) {
this.userId = userId;
this.name = name;
}
public int getUserId() { return userId; }
@Override
public String toString() { return "User{userId=" + userId + ", name='" + name + "'}"; }
}
public class TreeMapCustomKey {
public static void main(String[] args) {
// 傳入 Comparator,指定按 User 的 userId 升序排序
TreeMap<User, String> userMap = new TreeMap<>(Comparator.comparingInt(User::getUserId));
userMap.put(new User(2, "李四"), "部門A");
userMap.put(new User(1, "張三"), "部門B");
userMap.put(new User(3, "王五"), "部門C");
System.out.println("TreeMap 按自定義鍵(userId)升序:" + userMap);
// 輸出:{User{userId=1, name='張三'}=部門B, User{userId=2, name='李四'}=部門A, User{userId=3, name='王五'}=部門C}
}
}3. 方式 3:HashMap/LinkedHashMap 按鍵排序(轉(zhuǎn) List 后排序)
HashMap/LinkedHashMap 默認(rèn)不按鍵排序,若需按鍵排序,需先把「鍵集」轉(zhuǎn)成 List,再用
Collections.sort()排序
import java.util.*;
public class HashMapSortByKey {
public static void main(String[] args) {
// 1. 初始化 HashMap(無序)
HashMap<Integer, String> hashMap = new HashMap<>();
hashMap.put(3, "蘋果");
hashMap.put(1, "香蕉");
hashMap.put(2, "橘子");
// 2. 按鍵排序:步驟
// ① 取出所有鍵,轉(zhuǎn)成 List
List<Integer> keyList = new ArrayList<>(hashMap.keySet());
// ② 對(duì)鍵 List 排序(升序,默認(rèn))
Collections.sort(keyList);
// ③ (可選)降序排序:Collections.sort(keyList, Comparator.reverseOrder());
// 3. 遍歷排序后的鍵,輸出結(jié)果(保持排序后的順序)
System.out.println("HashMap 按鍵升序:");
for (Integer key : keyList) {
System.out.println(key + " → " + hashMap.get(key));
}
// 輸出:
// 1 → 香蕉
// 2 → 橘子
// 3 → 蘋果
}
}三、按「值」排序的實(shí)現(xiàn)方式
按值排序是所有 Map 的通用需求(比如統(tǒng)計(jì)詞頻后按次數(shù)排序),核心思路:
把 Map 的鍵值對(duì)(Entry)轉(zhuǎn)成 List,然后通過 Comparator 比較「值」的大小。
通用步驟:
- 取出 Map 中所有的鍵值對(duì)(
entrySet()); - 把 entrySet 轉(zhuǎn)成
List<Map.Entry<K, V>>; - 用
Collections.sort()或List.sort(),傳入 Comparator 比較「值」; - (可選)把排序后的 List 轉(zhuǎn)成新的 Map(如 LinkedHashMap,保留排序順序)。
示例 1:基礎(chǔ)類型值(String/Integer)按值升序/降序
以 HashMap 為例(LinkedHashMap 用法完全一致):
import java.util.*;
public class MapSortByValue {
public static void main(String[] args) {
// 1. 初始化 HashMap(鍵:水果,值:銷量)
HashMap<String, Integer> fruitSales = new HashMap<>();
fruitSales.put("蘋果", 100);
fruitSales.put("香蕉", 200);
fruitSales.put("橘子", 150);
// 2. 按值排序:步驟
// ① 取出所有鍵值對(duì),轉(zhuǎn)成 List
List<Map.Entry<String, Integer>> entryList = new ArrayList<>(fruitSales.entrySet());
// ② 按值升序排序(銷量從小到大)
entryList.sort(Comparator.comparingInt(Map.Entry::getValue));
System.out.println("按值(銷量)升序:");
entryList.forEach(entry -> System.out.println(entry.getKey() + " → " + entry.getValue()));
// 輸出:蘋果→100,橘子→150,香蕉→200
// ③ 按值降序排序(銷量從大到?。?
entryList.sort((e1, e2) -> Integer.compare(e2.getValue(), e1.getValue()));
// 簡化寫法:entryList.sort(Comparator.comparingInt(Map.Entry::getValue).reversed());
System.out.println("\n按值(銷量)降序:");
entryList.forEach(entry -> System.out.println(entry.getKey() + " → " + entry.getValue()));
// 輸出:香蕉→200,橘子→150,蘋果→100
// 3. (可選)轉(zhuǎn)成 LinkedHashMap 保留排序順序(方便后續(xù)使用)
LinkedHashMap<String, Integer> sortedMap = new LinkedHashMap<>();
for (Map.Entry<String, Integer> entry : entryList) {
sortedMap.put(entry.getKey(), entry.getValue());
}
System.out.println("\n排序后的 LinkedHashMap:" + sortedMap);
// 輸出:{香蕉=200, 橘子=150, 蘋果=100}
}
}示例 2:自定義對(duì)象值(如 User)按值排序
比如 Map 的值是 User 對(duì)象,按 User 的 age 排序:
import java.util.*;
// 自定義 User 類(作為值)
class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public int getAge() { return age; }
@Override
public String toString() { return "User{name='" + name + "', age=" + age + "}"; }
}
public class MapSortByCustomValue {
public static void main(String[] args) {
// 1. 初始化 Map(鍵:編號(hào),值:User 對(duì)象)
HashMap<String, User> userMap = new HashMap<>();
userMap.put("001", new User("張三", 25));
userMap.put("002", new User("李四", 20));
userMap.put("003", new User("王五", 30));
// 2. 按 User 的 age 升序排序
List<Map.Entry<String, User>> entryList = new ArrayList<>(userMap.entrySet());
entryList.sort(Comparator.comparingInt(e -> e.getValue().getAge()));
// 3. 輸出結(jié)果
System.out.println("按值(User.age)升序:");
entryList.forEach(entry -> System.out.println(entry.getKey() + " → " + entry.getValue()));
// 輸出:
// 002 → User{name='李四', age=20}
// 001 → User{name='張三', age=25}
// 003 → User{name='王五', age=30}
}
}四、避坑提示(小白必看)
- 鍵的可比較性:TreeMap 的鍵必須是可比較的(要么實(shí)現(xiàn) Comparable 接口,要么傳入 Comparator),否則會(huì)拋
ClassCastException; - 空值問題:HashMap 允許鍵/值為 null;TreeMap 不允許鍵為 null(會(huì)拋空指針),但允許值為 null;LinkedHashMap 允許鍵/值為 null;
- 排序后的數(shù)據(jù)存儲(chǔ):HashMap/LinkedHashMap 排序后,原 Map 順序不變,排序結(jié)果需通過 List 或新的 LinkedHashMap 保存;
- 效率問題:TreeMap 按鍵排序的時(shí)間復(fù)雜度是 O(logn)(紅黑樹特性);HashMap/LinkedHashMap 轉(zhuǎn) List 排序的時(shí)間復(fù)雜度是 O(nlogn)(基于快排)
五、總結(jié)(小白直接記)
| 需求 | 推薦 Map 類型 | 實(shí)現(xiàn)方式 |
|---|---|---|
| 按鍵自然升序 | TreeMap | 直接使用(無需額外代碼) |
| 按鍵自定義排序(降序/對(duì)象鍵) | TreeMap | 傳入 Comparator 接口 |
| HashMap/LinkedHashMap 按鍵排序 | 任意 | 鍵集轉(zhuǎn) List → Collections.sort() |
| 按值排序(任何場景) | 任意 | 鍵值對(duì)(Entry)轉(zhuǎn)成 List →Collections.sort() |
實(shí)際開發(fā)中:
- 若需長期維護(hù)「按鍵有序」的 Map → 直接用 TreeMap;
- 若只是臨時(shí)需要按鍵/值排序 → 用 HashMap + 手動(dòng)排序(更高效);
- 若需保留排序后的順序供后續(xù)使用 → 排序后轉(zhuǎn)成 LinkedHashMap。
到此這篇關(guān)于Java Map排序如何按照值按照鍵排序的文章就介紹到這了,更多相關(guān)java map排序內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
eclipse老是自動(dòng)跳到console解決辦法
eclipse啟動(dòng)服務(wù)后,想看一些properties信息或者別的,但老是自動(dòng)跳轉(zhuǎn)到console頁面,本文給大家介紹了解決辦法,對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-03-03
Spring Cloud Ribbon客戶端詳細(xì)介紹
Spring Cloud Ribbon 是一套基于 Netflix Ribbon 實(shí)現(xiàn)的客戶端負(fù)載均衡和服務(wù)調(diào)用工具。通過Spring Cloud的封裝,可以讓我們輕松地將面向服務(wù)的REST模版請(qǐng)求自動(dòng)轉(zhuǎn)換成客戶端負(fù)載均衡的服務(wù)調(diào)用2022-09-09
java中基本注解的知識(shí)點(diǎn)總結(jié)
在本篇文章里小編給大家整理的是一篇關(guān)于java中基本注解的知識(shí)點(diǎn)總結(jié),有需要的朋友們可以跟著學(xué)習(xí)下。2021-06-06
Java將文件內(nèi)容讀取為字符串的實(shí)現(xiàn)步驟
在Java編程中,經(jīng)常需要將文件內(nèi)容讀取為字符串進(jìn)行處理,比如配置文件讀取、文本數(shù)據(jù)解析等場景,不同版本的Java提供了多種實(shí)現(xiàn)方式,同時(shí)也有一些外部庫可以簡化操作,本文給大家介紹了Java將文件內(nèi)容讀取為字符串的實(shí)現(xiàn)步驟,需要的朋友可以參考下2025-06-06

