跳转至

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 小练习

  1. 用 ArrayList 存 10 个随机数,找出最大值和最小值
  2. 用 HashMap 统计一句话里每个字符出现的次数
  3. 用 HashSet 给一个 List 去重
  4. 遍历 Map,打印所有键值对

本章小结

  • List 有序可重复(ArrayList),Set 去重(HashSet),Map 键值对(HashMap)
  • getOrDefault 防 NPE
  • 遍历时删除用迭代器
  • 集合一定要配泛型
  • 排序用 Collections.sort 或 list.sort

下一章:12 异常处理

🏠 返回总站