Java Map排序如何按照值按照键排序

 更新时间:2025年11月12日 11:56:12   作者:Chasing Aurora  
该文章主要介绍Java中三种Map(HashMap、LinkedHashMap、TreeMap)的默认排序行为及实现按键排序和按值排序的方法,每种方法结合实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧

结论:只有 TreeMap 天生支持按键排序,HashMap/LinkedHashMap 需手动处理,按值排序所有 Map 都要额外实现

一、先理清 3 种 Map 的默认排序行为

Map 类型底层结构默认排序规则核心特点
HashMap哈希表无固定顺序(随机)查找快、无序、线程不安全
TreeMap红黑树按「键」自然排序(默认升序)有序(键)、查找效率中等、可自定义排序
LinkedHashMap哈希表 + 链表按「插入顺序」排序有序(插入顺序)、查找快、保留插入顺序

简单说:

  • 想默认按键有序 → 直接用 TreeMap;
  • 想保留插入顺序 → 用 LinkedHashMap;
  • 只想要查询快、不关心顺序 → 用 HashMap;
  • 按值排序 → 任何 Map 都要手动处理(因为 Map 本质是「键值对映射」,值不具备天然排序索引)。

二、按「键」排序的实现方式

按键排序的核心是:键必须是可比较的(实现 Comparable 接口,如 String、Integer、Long 等),如果是自定义对象作为键,需手动指定比较规则。

1. 方式 1:用 TreeMap (默认按键升序,无需额外代码)

TreeMap 天生支持按键排序,默认是「自然升序」(比如数字从小到大、字符串按字典序)。

import java.util.TreeMap;
public class MapSortByKey {
    public static void main(String[] args) {
        // 1. TreeMap 默认按键自然升序排序(键是 Integer 类型,可比较)
        TreeMap<Integer, String> treeMap = new TreeMap<>();
        treeMap.put(3, "苹果");
        treeMap.put(1, "香蕉");
        treeMap.put(2, "橘子");
        System.out.println("TreeMap 默认按键升序:" + treeMap);
        // 输出:{1=香蕉, 2=橘子, 3=苹果}(按键 1→2→3 排序)
    }
}

2. 方式 2:TreeMap 自定义键排序(比如降序、自定义对象键)

如果想按键降序,或键是自定义对象(比如 User),需要传入 Comparator 接口指定排序规则。

示例 2.1:TreeMap 按键降序

import java.util.Comparator;
import java.util.TreeMap;
public class MapSortByKeyDesc {
    public static void main(String[] args) {
        // 传入 Comparator.reverseOrder() 实现键降序
        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:自定义对象作为 TreeMap 的键(需指定比较规则)

比如用 User 对象作为键,按 userId 升序排序:

import java.util.Comparator;
import java.util.TreeMap;
// 自定义 User 类(作为键)
class User {
    private int userId;
    private String name;
    // 构造方法、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 按键排序(转 List 后排序)

HashMap/LinkedHashMap 默认不按键排序,若需按键排序,需先把「键集」转成 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. 按键排序:步骤
        // ① 取出所有键,转成 List
        List<Integer> keyList = new ArrayList<>(hashMap.keySet());
        // ② 对键 List 排序(升序,默认)
        Collections.sort(keyList);
        // ③ (可选)降序排序:Collections.sort(keyList, Comparator.reverseOrder());
        // 3. 遍历排序后的键,输出结果(保持排序后的顺序)
        System.out.println("HashMap 按键升序:");
        for (Integer key : keyList) {
            System.out.println(key + " → " + hashMap.get(key));
        }
        // 输出:
        // 1 → 香蕉
        // 2 → 橘子
        // 3 → 苹果
    }
}

三、按「值」排序的实现方式

按值排序是所有 Map 的通用需求(比如统计词频后按次数排序),核心思路:
把 Map 的键值对(Entry)转成 List,然后通过 Comparator 比较「值」的大小。

通用步骤:

  1. 取出 Map 中所有的键值对(entrySet());
  2. 把 entrySet 转成 List<Map.Entry<K, V>>
  3. Collections.sort()List.sort(),传入 Comparator 比较「值」;
  4. (可选)把排序后的 List 转成新的 Map(如 LinkedHashMap,保留排序顺序)。

示例 1:基础类型值(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. 按值排序:步骤
        // ① 取出所有键值对,转成 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. (可选)转成 LinkedHashMap 保留排序顺序(方便后续使用)
        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:自定义对象值(如 User)按值排序

比如 Map 的值是 User 对象,按 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(键:编号,值:User 对象)
        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. 输出结果
        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}
    }
}

四、避坑提示(小白必看)

  1. 键的可比较性:TreeMap 的键必须是可比较的(要么实现 Comparable 接口,要么传入 Comparator),否则会抛 ClassCastException
  2. 空值问题:HashMap 允许键/值为 null;TreeMap 不允许键为 null(会抛空指针),但允许值为 null;LinkedHashMap 允许键/值为 null;
  3. 排序后的数据存储:HashMap/LinkedHashMap 排序后,原 Map 顺序不变,排序结果需通过 List 或新的 LinkedHashMap 保存;
  4. 效率问题:TreeMap 按键排序的时间复杂度是 O(logn)(红黑树特性);HashMap/LinkedHashMap 转 List 排序的时间复杂度是 O(nlogn)(基于快排)

五、总结(小白直接记)

需求推荐 Map 类型实现方式
按键自然升序TreeMap直接使用(无需额外代码)
按键自定义排序(降序/对象键)TreeMap传入 Comparator 接口
HashMap/LinkedHashMap 按键排序任意键集转 List → Collections.sort()
按值排序(任何场景)任意键值对(Entry)转成 List →Collections.sort()

实际开发中:

  • 若需长期维护「按键有序」的 Map → 直接用 TreeMap;
  • 若只是临时需要按键/值排序 → 用 HashMap + 手动排序(更高效);
  • 若需保留排序后的顺序供后续使用 → 排序后转成 LinkedHashMap。

到此这篇关于Java Map排序如何按照值按照键排序的文章就介绍到这了,更多相关java map排序内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Spring Boot项目维护全局json数据代码实例

    Spring Boot项目维护全局json数据代码实例

    这篇文章主要介绍了Spring Boot项目维护全局json数据代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-02-02
  • Java数据结构之散列表详解

    Java数据结构之散列表详解

    散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。本文将为大家具体介绍一下散列表的原理及其代码实现
    2022-01-01
  • 实例分析Java泛型

    实例分析Java泛型

    本篇文章通过代码实例给大家讲述了Java泛型的相关知识点以及相关的代码分析,对此有兴趣的朋友学习下。
    2018-02-02
  • IDEA的部署设置改为war exploded运行项目出错问题

    IDEA的部署设置改为war exploded运行项目出错问题

    在使用IDEA配置warexploded部署时,可能会遇到路径问题或404错误,解决方法是进入Deployment设置,删除Application content中的/marry_war_exploded,使其为空,然后重新运行项目即可,这是一种有效的解决策略,希望能帮助到遇到同样问题的开发者
    2024-10-10
  • SpringDoc基本使用的方法示例

    SpringDoc基本使用的方法示例

    SpringDoc是基于Spring Boot的现代化API文档生成工具,下面就来介绍一下SpringDoc基本使用,具有一定的参考价值,感兴趣的可以了解一下
    2025-07-07
  • Java中MapStruct入门使用及对比

    Java中MapStruct入门使用及对比

    MapStruct是一个Java注解处理器框架,用于简化Java Bean之间的映射,本文主要介绍了Java中MapStruct入门使用及对比,感兴趣的可以了解一下
    2023-12-12
  • Kafka 日志存储实现过程

    Kafka 日志存储实现过程

    这篇文章主要为大家介绍了Kafka 日志存储的实现过程详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-05-05
  • Java操作Redis2种方法代码详解

    Java操作Redis2种方法代码详解

    这篇文章主要介绍了Java操作Redis2种方法代码详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04
  • 作为程序员必须掌握的Java虚拟机中的22个重难点(推荐0

    作为程序员必须掌握的Java虚拟机中的22个重难点(推荐0

    这篇文章主要介绍了Java虚拟机中22个重难点,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-03-03
  • Java二叉搜索树遍历操作详解【前序、中序、后序、层次、广度优先遍历】

    Java二叉搜索树遍历操作详解【前序、中序、后序、层次、广度优先遍历】

    这篇文章主要介绍了Java二叉搜索树遍历操作,结合实例形式详细分析了Java二叉搜索树前序、中序、后序、层次、广度优先遍历等相关原理与操作技巧,需要的朋友可以参考下
    2020-03-03

最新评论