Java Map集合学习笔记
·
Java Map集合学习笔记
一、Map集合概述
Map是Java集合框架中一个非常重要的接口,它用于存储键值对(key-value)映射关系的数据结构。与Collection接口不同,Map不继承自Collection,而是独立的接口体系。
Map的主要特点包括:
- 键值对存储:每个元素包含一个键(key)和一个值(value)
- 键唯一性:Map中不允许有重复的键
- 值可重复:不同的键可以对应相同的值
- 无序性:大多数Map实现不保证元素的顺序
Map接口的常用实现类有:
- HashMap:基于哈希表实现,无序,允许null键和null值
- LinkedHashMap:继承自HashMap,维护插入顺序
- TreeMap:基于红黑树实现,按键的自然顺序或Comparator排序
- Hashtable:线程安全的Map实现,不允许null键和null值
- ConcurrentHashMap:线程安全的高性能Map实现
二、Map核心方法解析
1. 基本操作方法
// 添加元素
V put(K key, V value); // 添加键值对,如果键已存在则替换值并返回旧值
// 获取元素
V get(Object key); // 根据键获取值
V getOrDefault(Object key, V defaultValue); // 获取值,不存在则返回默认值
// 删除元素
V remove(Object key); // 根据键删除键值对
// 判断方法
boolean containsKey(Object key); // 判断是否包含指定键
boolean containsValue(Object value); // 判断是否包含指定值
boolean isEmpty(); // 判断Map是否为空
int size(); // 返回键值对数量
// 清空Map
void clear();
2. 视图操作方法
Map提供了三种集合视图:
- keySet():返回所有键的Set集合
- values():返回所有值的Collection集合
- entrySet():返回所有键值对的Set集合
// 遍历Map的几种方式
Map<String, Integer> map = new HashMap<>();
// 1. 使用entrySet()遍历
for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
// 2. 使用keySet()遍历
for (String key : map.keySet()) {
System.out.println(key + ": " + map.get(key));
}
// 3. 使用forEach方法(Java8+)
map.forEach((k, v) -> System.out.println(k + ": " + v));
// 4. 使用迭代器
Iterator<Map.Entry<String, Integer>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, Integer> entry = iterator.next();
System.out.println(entry.getKey() + ": " + entry.getValue());
}
三、HashMap深度解析
HashMap是Map接口最常用的实现类,基于哈希表实现,具有以下特点:
- 允许null键和null值
- 非线程安全
- 不保证元素顺序
- 初始容量为16,负载因子为0.75
1. HashMap底层结构
JDK1.8后,HashMap采用数组+链表+红黑树的结构:
- 当链表长度超过8且数组长度大于64时,链表转为红黑树
- 当红黑树节点数小于6时,退化为链表
// HashMap部分源码
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
// ...
}
2. HashMap扩容机制
当元素数量超过阈值(容量*负载因子)时,HashMap会进行扩容:
- 创建新数组,大小为原数组的2倍
- 重新计算所有元素的哈希值并分配到新数组中
- 扩容是一个耗时的操作,应尽量避免频繁扩容
// 优化HashMap性能的建议
// 1. 预估元素数量,设置初始容量
Map<String, Integer> map = new HashMap<>(100);
// 2. 调整负载因子(特殊场景下)
Map<String, Integer> map = new HashMap<>(16, 0.5f);
四、TreeMap与排序
TreeMap是基于红黑树实现的NavigableMap,具有以下特点:
- 按键的自然顺序或Comparator排序
- 查询、插入、删除操作的时间复杂度为O(log n)
- 不允许null键(取决于Comparator)
1. 自然排序示例
Map<String, Integer> treeMap = new TreeMap<>();
treeMap.put("orange", 2);
treeMap.put("apple", 5);
treeMap.put("banana", 3);
// 输出顺序:apple, banana, orange
treeMap.forEach((k, v) -> System.out.println(k));
2. 自定义排序示例
// 按值排序的Comparator
Comparator<String> valueComparator = (k1, k2) -> {
int cmp = map.get(k1).compareTo(map.get(k2));
return cmp != 0 ? cmp : k1.compareTo(k2);
};
Map<String, Integer> sortedMap = new TreeMap<>(valueComparator);
sortedMap.putAll(map);
五、线程安全的Map实现
1. Hashtable
Hashtable是早期线程安全的Map实现:
- 所有方法都使用synchronized修饰
- 性能较差,不推荐使用
- 不允许null键和null值
2. ConcurrentHashMap
ConcurrentHashMap是推荐的线程安全Map实现:
- JDK1.7采用分段锁机制
- JDK1.8改用CAS+synchronized
- 高并发下性能优于Hashtable
// ConcurrentHashMap使用示例
ConcurrentMap<String, Integer> concurrentMap = new ConcurrentHashMap<>();
concurrentMap.put("one", 1);
concurrentMap.putIfAbsent("one", 100); // 不会替换已有值
六、Map工具类Collections
Collections类提供了一些操作Map的实用方法:
// 创建不可变Map
Map<String, Integer> unmodifiableMap = Collections.unmodifiableMap(map);
// 创建同步Map
Map<String, Integer> synchronizedMap = Collections.synchronizedMap(map);
// 空Map
Map<String, Integer> emptyMap = Collections.emptyMap();
七、Java8对Map的增强
Java8为Map接口添加了许多实用方法:
Map<String, Integer> map = new HashMap<>();
// 1. compute方法
map.compute("key", (k, v) -> v == null ? 1 : v + 1);
// 2. merge方法
map.merge("key", 1, (oldVal, newVal) -> oldVal + newVal);
// 3. getOrDefault
int value = map.getOrDefault("nonexistent", 0);
// 4. putIfAbsent
map.putIfAbsent("key", 100);
// 5. replaceAll
map.replaceAll((k, v) -> v * 2);
八、Map使用场景与最佳实践
1. 常见使用场景
- 缓存实现
- 数据字典
- 对象属性映射
- 计数器实现
2. 最佳实践
- 根据需求选择合适的Map实现
- 预估元素数量设置初始容量
- 高并发环境使用ConcurrentHashMap
- 需要排序时使用TreeMap
- 避免在迭代过程中修改Map
九、性能比较
不同Map实现的性能特点:
| 实现类 | 获取 | 插入 | 删除 | 遍历 | 线程安全 | 有序 |
|---|---|---|---|---|---|---|
| HashMap | O(1) | O(1) | O(1) | O(n) | 否 | 否 |
| LinkedHashMap | O(1) | O(1) | O(1) | O(n) | 否 | 插入顺序 |
| TreeMap | O(log n) | O(log n) | O(log n) | O(n) | 否 | 按键排序 |
| Hashtable | O(1) | O(1) | O(1) | O(n) | 是 | 否 |
| ConcurrentHashMap | O(1) | O(1) | O(1) | O(n) | 是 | 否 |
十、总结
Map集合是Java中极其重要的数据结构,几乎在所有Java应用中都有使用。理解不同Map实现的特点和适用场景,能够帮助我们编写出更高效、更健壮的代码。HashMap作为最常用的实现,其底层原理值得深入理解;TreeMap提供了排序功能;而ConcurrentHashMap则是高并发环境下的首选。随着Java版本的更新,Map接口也在不断丰富其功能,如Java8引入的流式操作和函数式方法大大简化了Map的操作。
在实际开发中,应根据具体需求选择合适的Map实现,并注意线程安全和性能优化问题。掌握Map集合的使用和原理,是Java开发者必备的核心技能之一。
更多推荐


所有评论(0)