11 集合框架¶
本章目标¶
- 理解集合框架:List / Set / Map
- 掌握 ArrayList、HashSet、HashMap 的增删改查
- 掌握集合的遍历方式
- 了解集合与泛型的配合
11.1 为什么需要集合¶
数组长度固定,增删元素麻烦。集合(Collection) 可以动态增删、自动扩容,是开发中用的最多的数据结构。
Java 集合框架核心三兄弟:
List 列表:有序、可重复 [a, b, c, a]
Set 集合:无序、不可重复 {a, b, c}
Map 映射:键值对,键不可重复 {name=小明, level=30}
11.2 List:ArrayList¶
最常用,底层是数组,自动扩容。
import java.util.ArrayList;
import java.util.List;
List<String> names = new ArrayList<>();
// 增
names.add("小明");
names.add("小红");
names.add("小明"); // 允许重复
// 删
names.remove("小红"); // 按内容删
names.remove(0); // 按下标删
// 改
names.set(0, "小刚"); // 替换第 0 个
// 查
names.get(0); // 取第 0 个
names.size(); // 长度(注意不是 length)
names.contains("小刚"); // 是否包含
names.isEmpty(); // 是否为空
names.indexOf("小刚"); // 找下标
// 清空
names.clear();
List.of 快速创建不可变列表
List<String> list = List.of("a", "b", "c"); // 不可变,不能 add/remove
11.3 Set:HashSet¶
自动去重,无序(不保证顺序):
import java.util.HashSet;
import java.util.Set;
Set<String> ids = new HashSet<>();
ids.add("player1");
ids.add("player2");
ids.add("player1"); // 重复添加无效
ids.size(); // 2
ids.contains("player1"); // true
ids.remove("player2");
模组里的 Set
已加载区块列表、已处理过的实体 ID、在线玩家集合——"去重 + 快速查找"的场景都用 Set。HashSet 查找是 O(1),比 List 快很多。
LinkedHashSet / TreeSet¶
LinkedHashSet:去重 + 保持插入顺序TreeSet:去重 + 自动排序(元素要实现 Comparable)
11.4 Map:HashMap¶
键值对存储,按键取值,键不能重复:
import java.util.HashMap;
import java.util.Map;
Map<String, Integer> playerLevels = new HashMap<>();
// 增/改
playerLevels.put("小明", 30);
playerLevels.put("小红", 45);
playerLevels.put("小明", 31); // 键已存在 → 覆盖为 31
// 查
playerLevels.get("小明"); // 31
playerLevels.get("路人"); // null(不存在返回 null)
playerLevels.getOrDefault("路人", 0); // 不存在返回默认值 0
// 判断
playerLevels.containsKey("小明"); // true
playerLevels.containsValue(45); // true
playerLevels.size();
playerLevels.isEmpty();
// 删
playerLevels.remove("小红");
playerLevels.clear();
get 返回 null 的坑
playerLevels.get("路人") + 1 会 NPE!用 getOrDefault(key, 0) 或先判空。
11.5 遍历集合¶
增强 for(最常用)¶
List<String> names = List.of("小明", "小红", "小刚");
for (String name : names) {
System.out.println(name);
}
Map<String, Integer> map = new HashMap<>();
// 遍历键值对
for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey() + " -> " + entry.getValue());
}
// 只遍历键 / 值
for (String key : map.keySet()) { ... }
for (Integer v : map.values()) { ... }
迭代器(遍历时删除用)¶
Iterator<String> it = names.iterator();
while (it.hasNext()) {
String name = it.next();
if (name.equals("小明")) {
it.remove(); // ✅ 安全删除
}
}
遍历时直接 remove 会报错
for (String n : list) { list.remove(n); } → ConcurrentModificationException。要么用迭代器 remove,要么收集后统一删。
11.6 集合与泛型¶
集合强烈建议配合泛型,指定元素类型,编译器帮你检查:
List<String> list = new ArrayList<>(); // 只能装 String
Map<String, Integer> map = new HashMap<>(); // 键 String,值 Integer
不加泛型会怎样?
List list = new ArrayList(); // 裸类型,什么都能装
list.add("hello");
list.add(123);
String s = (String) list.get(0); // 要自己强转,容易 ClassCastException
11.7 集合的排序¶
List<Integer> nums = new ArrayList<>(List.of(5, 2, 8, 1));
java.util.Collections.sort(nums); // [1, 2, 5, 8]
java.util.Collections.reverse(nums); // 反转
// 自定义对象排序(第 16 章 Lambda 细讲)
List<Player> players = new ArrayList<>();
players.sort((p1, p2) -> p2.getLevel() - p1.getLevel()); // 按等级降序
11.8 实战:模组场景¶
// 记录每个玩家击杀数
Map<String, Integer> killCount = new HashMap<>();
killCount.put("小明", killCount.getOrDefault("小明", 0) + 1); // 击杀 +1
// 在线玩家列表(去重)
Set<String> online = new HashSet<>();
online.add("小明");
online.add("小红");
online.remove("小红"); // 下线
// 按等级排序显示排行榜
List<Map.Entry<String, Integer>> list = new ArrayList<>(killCount.entrySet());
list.sort((a, b) -> b.getValue() - a.getValue()); // 降序
11.9 小练习¶
- 用 ArrayList 存 10 个随机数,找出最大值和最小值
- 用 HashMap 统计一句话里每个字符出现的次数
- 用 HashSet 给一个 List 去重
- 遍历 Map,打印所有键值对
本章小结¶
- List 有序可重复(ArrayList),Set 去重(HashSet),Map 键值对(HashMap)
- getOrDefault 防 NPE
- 遍历时删除用迭代器
- 集合一定要配泛型
- 排序用 Collections.sort 或 list.sort
下一章:12 异常处理