🔥 本文深入剖析Java集合框架中的TreeMap,从基础应用到实战案例,带你全面掌握这个重要的有序集合类。本文是TreeMap系列的上篇,主要关注基础用法与实战应用,下篇将深入源码与面试重点。
📚 系列专栏推荐:
一、TreeMap简介
1. 什么是TreeMap?
TreeMap是Java集合框架中的一个重要实现,它是一个基于红黑树实现的有序键值对集合。与HashMap不同,TreeMap可以保证其中的元素按照键的自然顺序或自定义顺序进行排序。
简单来说,TreeMap就像是一个会自动排序的Map,当你需要一个有序的键值对集合时,它就是最佳选择。
2. TreeMap的特点
2.1 有序性
TreeMap<String, Integer> treeMap = new TreeMap<>();
treeMap.put("banana", 2);
treeMap.put("apple", 1);
treeMap.put("orange", 3);
// 输出将按键的字母顺序排序:apple, banana, orange
System.out.println(treeMap);
2.2 可自定义排序
// 自定义排序规则(按值降序)
TreeMap<String, Integer> customMap = new TreeMap<>((k1, k2) ->
treeMap.get(k2).compareTo(treeMap.get(k1)));
2.3 不允许null键
- HashMap允许一个null键和多个null值
- TreeMap不允许null键(会抛出NullPointerException),但允许null值
2.4 线程不安全
- 多线程环境下需要外部同步
- 可以使用Collections.synchronizedSortedMap()进行包装
3. 与HashMap的区别
特性 | TreeMap | HashMap |
---|---|---|
数据结构 | 红黑树 | 数组+链表+红黑树 |
有序性 | 有序 | 无序 |
性能 | 大部分操作 O(log n) | 大部分操作 O(1) |
null键 | 不支持 | 支持 |
内存占用 | 相对较大 | 相对较小 |
使用场景 | 需要排序的场景 | 一般键值对存储 |
4. 使用建议
- 当需要按键排序时,使用TreeMap
- 当不需要排序时,使用HashMap(性能更好)
- 数据量大且需要排序时,考虑先用HashMap存储,需要时再排序
- 需要频繁按序遍历时,TreeMap是好选择
💡 小贴士:TreeMap的有序性是以性能为代价的,如果你不需要有序性,建议使用HashMap。
5. 常见应用场景
- 词频统计与排序
TreeMap<String, Integer> wordCount = new TreeMap<>();
String text = "hello world hello java";
for (String word : text.split(" ")) {
wordCount.put(word, wordCount.getOrDefault(word, 0) + 1);
}
// 自动按单词字母顺序排序输出
System.out.println(wordCount); // {hello=2, java=1, world=1}
- 范围查询
TreeMap<Integer, String> prices = new TreeMap<>();
prices.put(100, "商品A");
prices.put(200, "商品B");
prices.put(300, "商品C");
// 获取价格在200以下的商品
System.out.println(prices.headMap(200)); // {100=商品A}
6. 性能注意事项
- 插入/删除/查找操作的时间复杂度均为O(log n)
- 数据量较大时,性能差异会更明显
- 如果不需要排序功能,优先使用HashMap
- 对于需要频繁修改的场景,要谨慎使用
二、基础用法详解
1. 创建TreeMap
TreeMap提供了多种构造方法,让我们来看看最常用的几种:
// 1. 默认构造,按键的自然顺序排序
TreeMap<String, Integer> map1 = new TreeMap<>();
// 2. 使用比较器构造,自定义排序规则
TreeMap<String, Integer> map2 = new TreeMap<>((s1, s2) -> s2.compareTo(s1)); // 反序
// 3. 从已有Map构造
Map<String, Integer> existingMap = new HashMap<>();
TreeMap<String, Integer> map3 = new TreeMap<>(existingMap);
2. 增删改查操作
2.1 添加元素
TreeMap<String, Integer> scores = new TreeMap<>();
// 添加单个元素
scores.put("张三", 95);
scores.put("李四", 88);
// 批量添加
Map<String, Integer> newScores = new HashMap<>();
newScores.put("王五", 90);
newScores.put("赵六", 85);
scores.putAll(newScores);
2.2 删除元素
// 根据键删除
scores.remove("张三");
// 条件删除
scores.remove("李四", 88); // 只有当值为88时才删除
// 清空所有
scores.clear();
2.3 修改元素
// 直接修改
scores.put("张三", 96); // 覆盖原有值
// 计算并修改
scores.compute("张三", (k, v) -> v + 2); // 加2分
scores.computeIfPresent("张三", (k, v) -> v + 2); // 存在时才修改
scores.computeIfAbsent("张三", k -> 60); // 不存在时才添加
2.4 查询元素
// 获取单个值
Integer score = scores.get("张三");
Integer defaultScore = scores.getOrDefault("王五", 0);
// 检查存在
boolean hasKey = scores.containsKey("张三");
boolean hasValue = scores.containsValue(95);
// 获取大小
int size = scores.size();
boolean isEmpty = scores.isEmpty();
3. 有序遍历方式