253. Java 集合 - 访问和操作 Map 的视图(Views)
1. 🧩 获取 Map 的不同视图
在 Java 中,Map 提供了三种常用的“视图”,让我们分别访问键、值或者键值对:
| 方法 | 返回类型 | 内容说明 |
|---|---|---|
keySet() | Set<K> | 返回 Map 中所有的键 |
values() | Collection<V> | 返回 Map 中所有的值 |
entrySet() | Set<Map.Entry<K,V>> | 返回 Map 中所有键值对(Entry) |
这些集合**是由 Map 支持(backed)**的,意味着:
- 改变集合(比如移除元素)会影响原
Map。 - 改变
Map也会影响这些集合。
📖 示例:访问 Keys、Values 和 Entries
import java.util.*;
public class MapViewExample {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<>();
map.put(1, "one");
map.put(2, "two");
map.put(3, "three");
map.put(4, "four");
map.put(5, "five");
// 获取所有键
Set<Integer> keys = map.keySet();
System.out.println("Keys: " + keys);
// 获取所有值
Collection<String> values = map.values();
System.out.println("Values: " + values);
// 获取所有键值对
Set<Map.Entry<Integer, String>> entries = map.entrySet();
System.out.println("Entries: " + entries);
}
}
🖨️ 输出结果:
Keys: [1, 2, 3, 4, 5]
Values: [one, two, three, four, five]
Entries: [1=one, 2=two, 3=three, 4=four, 5=five]
2. 🗑️ 通过视图修改 Map
因为这些视图是与原 Map 联动的,所以:
- 从 keySet 中移除一个键,相应的键值对会从 Map 中消失。
- 从 values 中移除一个值,只会删除第一次出现该值的键值对。
✨ 示例:通过 keySet() 移除键
public class KeySetRemoveExample {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<>();
map.put(1, "one");
map.put(2, "two");
map.put(3, "three");
Set<Integer> keys = map.keySet();
keys.remove(2); // 移除键 2
System.out.println("Map after removing key 2: " + map);
}
}
🖨️ 输出:
Map after removing key 2: {1=one, 3=three}
✅ 可以看到,删除 keySet() 中的元素,直接影响了原 Map。
✨ 示例:通过 values() 移除值
public class ValuesRemoveExample {
public static void main(String[] args) {
Map<Integer, String> map = Map.ofEntries(
Map.entry(1, "alpha"),
Map.entry(2, "beta"),
Map.entry(3, "alpha"),
Map.entry(4, "gamma")
);
System.out.println("Map before removal: " + map);
// 复制成可变的 HashMap
map = new HashMap<>(map);
map.values().remove("alpha"); // 只会移除第一个找到的 "alpha"
System.out.println("Map after removing 'alpha': " + map);
}
}
🖨️ 输出:
Map before removal: {1=alpha, 2=beta, 3=alpha, 4=gamma}
Map after removing 'alpha': {2=beta, 3=alpha, 4=gamma}
⚠️ 注意:
- 只移除了 第一个
"alpha"对应的键值对。 - 在
HashMap中,元素顺序不可预测,所以无法提前确定哪一个会被删除。
3. 🚫 视图的限制
虽然可以删除元素,但不能添加新元素到这些视图中!
例如:
keys.add(7); // 会抛出 UnsupportedOperationException
values.add("seven"); // 也会抛出 UnsupportedOperationException
⛔ 不能直接往 keySet() 或 values() 中新增元素。要新增数据,必须通过 put(key, value) 添加到原 Map!
4. 🔥 最佳实践:遍历 Map 的推荐方式
如果你需要遍历 Map 中的键值对,最推荐的方式是直接遍历 entrySet():
📖 示例:使用 entrySet 高效遍历
public class EntrySetTraversalExample {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<>();
map.put(10, "ten");
map.put(20, "twenty");
map.put(30, "thirty");
for (Map.Entry<Integer, String> entry : map.entrySet()) {
System.out.println(entry.getKey() + " -> " + entry.getValue());
}
}
}
🖨️ 输出:
10 -> ten
20 -> twenty
30 -> thirty
✅ 比起遍历 keySet() 再通过 get(key) 获取值,遍历 entrySet() 更高效且直观!
🎯 小结
| 视图方法 | 功能 | 是否能修改内容 | 是否能新增元素 |
|---|---|---|---|
keySet() | 访问所有键 | 可以删除键 | ❌ 不能新增键 |
values() | 访问所有值 | 可以删除第一个匹配的值 | ❌ 不能新增值 |
entrySet() | 访问所有键值对 | 可以删除Entry | ❌ 不能新增Entry |
👀 互动问题
问题1:values().remove("X") 为什么只能删除第一个匹配值?
答案示例:因为一个值可能对应多个键,
values()只删除遇到的第一个匹配项,且在HashMap中顺序不可预测。
问题2:能不能通过 keySet().add(key) 添加新的键到 Map?
答案示例:不能,会抛出
UnsupportedOperationException;新增必须用put()方法。
问题3:为什么遍历 Map 推荐用 entrySet()?
答案示例:遍历
entrySet()能一次性同时拿到键和值,性能更好,比每次取 key 再get()取 value 高效。