Map 核心方法:视图与批量操作
Map 的三类视图
Map 不像 List 那样直接存储元素,它存储的是「键值对」。访问这些键值对有三种方式:
Map 的三个视图
│
├── keySet() → Set<K> 所有 key
├── values() → Collection<V> 所有 value
└── entrySet() → Set<Entry<K,V>> 所有键值对重要:这三个返回的都是视图,不是副本。对视图的修改会影响原 Map。
keySet():所有 key
java
Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);
// 获取所有 key
Set<String> keys = map.keySet();
System.out.println(keys); // [a, b, c]
// 通过 keySet 删除
keys.remove("a"); // map 中也会删除 a=1
// 通过 keySet 遍历
for (String key : map.keySet()) {
System.out.println(key);
}keySet 是可修改的视图
java
// keySet().remove(key) 会从原 Map 中删除
map.keySet().remove("b");
System.out.println(map); // {c=3}
// 但 keySet().add(key) 呢?
// ❌ UnsupportedOperationException
// map.keySet().add("d"); // 不支持,因为 Map 没有 add 方法values():所有 value
java
Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);
// 获取所有 value
Collection<Integer> values = map.values();
System.out.println(values); // [1, 2, 3]
// values().remove(value) 会从原 Map 中删除
values.remove(2); // 删除 b=2
System.out.println(map); // {a=1, c=3}entrySet():所有键值对
entrySet 是最有用的视图,因为可以同时获取 key 和 value:
java
Map<String, Integer> map = new HashMap<>();
map.put("apple", 3);
map.put("banana", 1);
map.put("cherry", 2);
// 遍历 entrySet
for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey() + " = " + entry.getValue());
}
// 修改 entry 的 value
for (Map.Entry<String, Integer> entry : map.entrySet()) {
if (entry.getValue() > 1) {
entry.setValue(entry.getValue() * 2);
}
}
// {apple=6, banana=1, cherry=4}Map.Entry 接口
每个 entry 都是一个 Map.Entry<K, V> 对象:
java
public interface Map.Entry<K, V> {
K getKey(); // 获取 key
V getValue(); // 获取 value
V setValue(V); // 设置 value(可变 Map 支持)
// 比较、哈希等方法...
}创建 Entry
java
// JDK 9+:Map.entry() 便捷方法
Map.Entry<String, Integer> entry = Map.entry("apple", 3);
System.out.println(entry.getKey()); // apple
System.out.println(entry.getValue()); // 3按 key 或 value 排序 entry
java
Map<String, Integer> map = new HashMap<>();
map.put("apple", 3);
map.put("banana", 1);
map.put("cherry", 2);
// 按 key 排序
List<Map.Entry<String, Integer>> byKey = new ArrayList<>(map.entrySet());
Collections.sort(byKey, Map.Entry.comparingByKey());
System.out.println(byKey); // [apple, banana, cherry]
// 按 value 排序
List<Map.Entry<String, Integer>> byValue = new ArrayList<>(map.entrySet());
Collections.sort(byValue, Map.Entry.comparingByValue());
System.out.println(byValue); // [banana, cherry, apple]批量操作
putAll():合并另一个 Map
java
Map<String, Integer> map1 = new HashMap<>();
map1.put("a", 1);
map1.put("b", 2);
Map<String, Integer> map2 = new HashMap<>();
map2.put("b", 20); // 覆盖
map2.put("c", 30);
map1.putAll(map2);
System.out.println(map1); // {a=1, b=20, c=30}keySet.removeIf():批量删除
JDK 8+ 的 removeIf 可以批量删除满足条件的元素:
java
Map<String, Integer> map = new HashMap<>();
map.put("apple", 3);
map.put("banana", 1);
map.put("cherry", 2);
map.put("date", 4);
// 删除 value > 2 的条目
map.entrySet().removeIf(e -> e.getValue() > 2);
System.out.println(map); // {banana=1, cherry=2}clear():清空 Map
java
Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.clear();
System.out.println(map); // {}子视图:subMap / headMap / tailMap
这是 TreeMap(和 SortedMap)独有的功能:
java
TreeMap<Integer, String> map = new TreeMap<>();
map.put(1, "one");
map.put(5, "five");
map.put(10, "ten");
map.put(15, "fifteen");
map.put(20, "twenty");
// subMap:区间视图(左闭右开)
SortedMap<Integer, String> sub = map.subMap(5, 15);
System.out.println(sub); // {5=five, 10=ten}
// headMap:头部视图(< key)
SortedMap<Integer, String> head = map.headMap(10);
System.out.println(head); // {1=one, 5=five}
// tailMap:尾部视图(>= key)
SortedMap<Integer, String> tail = map.tailMap(15);
System.out.println(tail); // {15=fifteen, 20=twenty}
// NavigableMap 提供更精细的控制
NavigableMap<Integer, String> nav = map.subMap(1, true, 20, false);
System.out.println(nav); // {1=one, 5=five, 10=ten, 15=fifteen}注意:HashMap 不支持这些操作。
视图与原 Map 的关系
java
Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
// 视图会反映原 Map 的变化
map.put("c", 3);
System.out.println(map.keySet()); // [a, b, c]
// 反过来,修改视图也会影响原 Map
map.keySet().remove("a");
System.out.println(map); // {b=2, c=3}
// 通过 values().clear() 清空整个 Map
map.values().clear();
System.out.println(map); // {}不可变视图
Collections.unmodifiableXxx() 可以创建只读视图:
java
Map<String, Integer> original = new HashMap<>();
original.put("a", 1);
// 不可变包装
Map<String, Integer> readOnly = Collections.unmodifiableMap(original);
readOnly.put("b", 2); // UnsupportedOperationException
// 但修改原 Map 会影响不可变视图
original.put("c", 3);
System.out.println(readOnly); // {a=1, c=3}方法总结
| 视图/批量方法 | 说明 | 适用范围 |
|---|---|---|
keySet() | 返回所有 key | 所有 Map |
values() | 返回所有 value | 所有 Map |
entrySet() | 返回所有键值对 | 所有 Map |
putAll(map) | 合并另一个 Map | 所有 Map |
clear() | 清空所有元素 | 所有 Map |
entrySet().removeIf() | 批量删除 | JDK 8+ |
subMap(head/tail) | 子区间视图 | SortedMap/TreeMap |
Collections.unmodifiableXxx() | 只读视图 | 所有 Map |
总结
| 要点 | 说明 |
|---|---|
| 视图特性 | keySet/values/entrySet 的修改影响原 Map |
| 遍历推荐 | for (Map.Entry<K,V> e : map.entrySet()) |
| 批量删除 | entrySet().removeIf(predicate) |
| 不可变包装 | Collections.unmodifiableMap() |
| 子视图 | 只有 SortedMap/TreeMap 支持 |
一句话:Map 的视图是原 Map 的「窗户」——看得见、摸得着(也会影响原 Map)。
