一、前置基础

1. 关系梳理

  1. Map:键值对存储 key-value,key 唯一,value 可重复;
    • 实现类:HashMap(主流)、TreeMapLinkedHashMap
  2. Set:元素不可重复集合,底层绝大多数基于 Map 实现
    • HashSet:底层 HashMap,存元素做 key,固定占位 Object 做 value
    • LinkedHashSetLinkedHashMap,有序
    • TreeSetTreeMap,自动排序

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。

遍历三种方式

  1. 增强 for 循环

java

for(String s : set){}
  1. Iterator 迭代器(支持遍历中删除)
  2. forEach 函数式

三、HashMap vs HashSet 核心对比

  1. 存储结构
    • HashMap:key-value 键值对
    • HashSet:单个元素,底层 HashMap,元素作为 key
  2. 唯一性约束
    • HashMap:key 唯一,value 可重复
    • HashSet:所有元素唯一
  3. 常用场景
    • HashMap:缓存、映射关系、存储对象属性
    • HashSet:去重、判断元素是否存在、交集差集运算
  4. 获取元素
    • 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

五、常见坑点总结

  1. HashMap key 重写equals()hashCode(),自定义对象不重写会判断重复失效;
  2. HashSet 存自定义对象同样需要重写equals+hashCode
  3. get () 无 key 返回 null,优先使用getOrDefault避免空指针;
  4. 多线程下 HashMap 扩容会死循环,并发使用 ConcurrentHashMap;
  5. HashSet 无序,需要有序选择 LinkedHashSet,需要排序选择 TreeSet;
  6. entrySet 遍历效率远高于 keySet+get,大数据量优先使用 entrySet;
  7. remove (key,value) 必须键值同时匹配才删除,只传 key 直接删除该键。
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐