Java HashMap & Set
一、前置基础
1. 关系梳理
Map:键值对存储key-value,key 唯一,value 可重复;- 实现类:
HashMap(主流)、TreeMap、LinkedHashMap
- 实现类:
Set:元素不可重复集合,底层绝大多数基于 Map 实现HashSet:底层HashMap,存元素做 key,固定占位 Object 做 valueLinkedHashSet:LinkedHashMap,有序TreeSet:TreeMap,自动排序
2. 核心特性 HashMap
- 键唯一,允许 key/value 为 null(最多 1 个 null key)
- 无序,不保证存入顺序;
LinkedHashMap保证插入顺序 - 底层:数组 + 链表 + 红黑树,负载因子 0.75,扩容 2 倍
- 线程不安全,多线程用
ConcurrentHashMap
3. 核心特性 HashSet
- 元素不可重复,允许一个 null 元素
- 无序,底层完全复用 HashMap,仅封装 key 操作
- 无索引,不能通过下标遍历
第一部分:HashMap 全部常用方法详解
1. 构造方法(4 种)
java
// 1. 默认构造:容量16,负载因子0.75
HashMap<K,V> map = new HashMap<>();
// 2. 指定初始容量
HashMap<String,Integer> map = new HashMap<>(32);
// 3. 指定容量 + 负载因子
HashMap<String,Integer> map = new HashMap<>(32, 0.6f);
// 4. 传入已有Map复制
HashMap<String,Integer> map = new HashMap<>(oldMap);
2. 增 / 改操作
put(K key, V value)
功能:存入键值对;key 存在则覆盖旧 value,返回旧值;不存在返回 null
java
HashMap<String, Integer> map = new HashMap<>();
Integer old = map.put("张三", 18);
System.out.println(old); // null
old = map.put("张三", 20);
System.out.println(old); // 18 被覆盖
putIfAbsent(K key, V value)
仅 key 不存在时才存入,存在不覆盖,返回原有值 适合:不存在才新增,避免覆盖
java
map.putIfAbsent("李四", 22);
map.putIfAbsent("张三", 99); // 张三已存在,不修改
putAll(Map<? extends K, ? extends V> m)
批量合并另一个 map,重复 key 同样覆盖
java
HashMap<String,Integer> temp = new HashMap<>();
temp.put("王五",30);
map.putAll(temp);
3. 查询操作
get(Object key)
根据 key 取值,无 key 返回 null
java
Integer age = map.get("张三");
getOrDefault(Object key, V defaultValue)
key 不存在返回默认值,避免空指针(高频推荐)
java
// 没有"赵六"则返回0
int age = map.getOrDefault("赵六", 0);
containsKey(Object key)
判断是否存在指定 key,返回 boolean
java
if(map.containsKey("张三")){
System.out.println("存在该键");
}
containsValue(Object value)
判断是否存在指定 value,遍历整张表,效率低
java
map.containsValue(18);
4. 删除操作
remove(Object key)
根据 key 删除,返回被删除的 value;无 key 返回 null
java
Integer delVal = map.remove("张三");
remove(Object key, Object value)
键值匹配才删除,匹配成功返回 true,否则 false
java
// 只有张三对应值是20才删除
map.remove("张三",20);
5. 替换更新
replace(K key, V newValue)
key 存在才替换 value,返回旧值;不存在不操作
java
map.replace("李四", 25);
replace(K key, V oldValue, V newValue)
键 + 旧值同时匹配才替换
java
map.replace("李四",25,26);
replaceAll(BiFunction)
批量替换所有 value,基于原有键值计算新值
java
// 所有数字+1
map.replaceAll((k,v) -> v + 1);
6. 大小、判空、清空
size()
返回键值对总数量
java
int size = map.size();
isEmpty()
判断 map 是否为空,size==0 返回 true
java
map.isEmpty();
clear()
清空所有键值对,容量不变
java
map.clear();
7. 获取视图集合(遍历必备)
keySet ():获取所有 key 集合 Set<K>
java
Set<String> keys = map.keySet();
for(String key : keys){
System.out.println(key + "=" + map.get(key));
}
values ():获取所有 value 集合 Collection<V>
java
Collection<Integer> values = map.values();
for(Integer v : values){
System.out.println(v);
}
entrySet ():获取键值对实体 Set<Map.Entry<K,V>>(最高效遍历)
java
Set<Map.Entry<String,Integer>> entries = map.entrySet();
for(Map.Entry<String,Integer> entry : entries){
String k = entry.getKey();
Integer v = entry.getValue();
}
8. 遍历专用函数式方法
forEach(BiConsumer)
java
map.forEach((k,v) -> {
System.out.println(k + ":" + v);
});
9. 计算缓存方法(Java8 + 高频)
computeIfAbsent(K key, Function)
key 不存在,执行函数生成 value 存入并返回;存在直接返回 value 典型场景:Map 嵌套集合
java
// key不存在新建ArrayList,存在直接返回list
map.computeIfAbsent("学生列表", k -> new ArrayList<>()).add("小明");
computeIfPresent(K key, BiFunction)
key 存在才执行函数更新 value
java
map.computeIfPresent("张三", (k,v) -> v + 1);
compute(K key, BiFunction)
无论 key 是否存在,都执行函数更新 / 新增
java
map.compute("张三", (k,v) -> v == null ? 1 : v+1);
merge(K key, V value, BiFunction)
合并 value,不存在则存入;存在执行函数合并新旧值
java
// 相同key数字累加
map.merge("计数", 1, Integer::sum);
10. 克隆 & 相等判断
clone()
浅拷贝,返回新 HashMap
java
HashMap<String,Integer> newMap = (HashMap) map.clone();
equals(Object o)
键值对完全相同返回 true;==判断地址,equals判断内容
hashCode()
返回哈希值,HashMap 重写,用于比较两个 map 是否相等
第二部分:HashSet 全套方法详解
底层:private transient HashMap<E,Object> map; 存入元素作为 key,统一常量PRESENT = new Object()作为 value 占位。
1. 构造方法
java
// 空集合
HashSet<String> set = new HashSet<>();
// 指定初始容量
HashSet<String> set = new HashSet<>(16);
// 容量+负载因子
HashSet<String> set = new HashSet<>(16,0.75f);
// 传入集合初始化
List<String> list = Arrays.asList("a","b");
HashSet<String> set = new HashSet<>(list);
2. 新增 add (E e)
添加元素,返回 boolean:
- true:元素不存在,添加成功
- false:元素已存在,重复不存入
java
set.add("苹果");
set.add("苹果"); // 返回false,去重
3. 查询判断
contains(Object o)
集合是否包含该元素
jav
if(set.contains("苹果")){}
size()
元素个数
isEmpty()
是否无元素
4. 删除
remove(Object o)
删除元素,存在返回 true,否则 false
java
set.remove("苹果");
clear()
清空全部元素
removeIf (Predicate) Java8 批量条件删除
java
// 删除长度大于3的字符串
set.removeIf(s -> s.length() > 3);
5. 集合转换、批量操作
addAll(Collection<? extends E> c)
批量添加集合所有元素,自动去重
java
List<String> list = Arrays.asList("香蕉","橘子");
set.addAll(list);
containsAll(Collection<?> c)
是否包含传入集合全部元素
java
set.containsAll(Arrays.asList("苹果","香蕉"));
retainAll(Collection<?> c)
取交集:只保留两边都存在的元素
java
set.retainAll(Arrays.asList("苹果","橘子"));
removeAll(Collection<?> c)
删除传入集合中所有匹配元素
java
set.removeAll(Arrays.asList("香蕉"));
6. 遍历相关
iterator () 获取迭代器
java
Iterator<String> it = set.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
forEach (Consumer) 函数式遍历
java
set.forEach(s -> System.out.println(s));
toArray () 转数组
java
Object[] arr = set.toArray();
String[] strArr = set.toArray(new String[0]);
7. 克隆、相等
clone () 浅拷贝
java
HashSet<String> newSet = (HashSet) set.clone();
equals()、hashCode()
重写方法,比较集合内元素是否完全一致
8. 补充:Set 通用特性相关方法
无法使用的操作
Set 无下标、无 get (int index),不能通过索引取值; 无替换元素方法,只能先 remove 再 add。
遍历三种方式
- 增强 for 循环
java
for(String s : set){}
- Iterator 迭代器(支持遍历中删除)
- forEach 函数式
三、HashMap vs HashSet 核心对比
- 存储结构
- HashMap:key-value 键值对
- HashSet:单个元素,底层 HashMap,元素作为 key
- 唯一性约束
- HashMap:key 唯一,value 可重复
- HashSet:所有元素唯一
- 常用场景
- HashMap:缓存、映射关系、存储对象属性
- HashSet:去重、判断元素是否存在、交集差集运算
- 获取元素
- HashMap:通过 key 直接取值 O (1)
- HashSet:无 key,只能遍历 / 判断是否存在
四、高频开发代码示例汇总
1. HashMap 遍历三种方式
java
HashMap<String,Integer> map = new HashMap<>();
map.put("a",1);
map.put("b",2);
// 1. entrySet 最优
for(Map.Entry<String,Integer> entry : map.entrySet()){
System.out.println(entry.getKey() + " " + entry.getValue());
}
// 2. keySet
for(String k : map.keySet()){
System.out.println(k + map.get(k));
}
// 3. forEach
map.forEach((k,v)-> System.out.println(k));
2. HashSet 快速去重
java
List<Integer> list = Arrays.asList(1,2,2,3,3,3);
HashSet<Integer> set = new HashSet<>(list);
// 自动去除重复数字
3. HashMap 分组(computeIfAbsent 经典场景)
java
HashMap<String, List<Integer>> groupMap = new HashMap<>();
// 把相同key的数据存入同一个list
groupMap.computeIfAbsent("一班", k -> new ArrayList<>()).add(90);
groupMap.computeIfAbsent("一班", k -> new ArrayList<>()).add(88);
4. 合并 value 计数 merge
java
HashMap<String, Integer> countMap = new HashMap<>();
countMap.merge("订单", 1, Integer::sum);
countMap.merge("订单", 1, Integer::sum);
// 订单对应值为2
五、常见坑点总结
- HashMap key 重写
equals()和hashCode(),自定义对象不重写会判断重复失效; - HashSet 存自定义对象同样需要重写
equals+hashCode; - get () 无 key 返回 null,优先使用
getOrDefault避免空指针; - 多线程下 HashMap 扩容会死循环,并发使用 ConcurrentHashMap;
- HashSet 无序,需要有序选择 LinkedHashSet,需要排序选择 TreeSet;
- entrySet 遍历效率远高于 keySet+get,大数据量优先使用 entrySet;
- remove (key,value) 必须键值同时匹配才删除,只传 key 直接删除该键。
更多推荐



所有评论(0)