Java 集合框架
实际开发中处理"一组数据"远比单值多——一群用户、一组订单、键值对配置。Java 集合框架(Java Collections Framework)提供了一整套成熟的数据结构,日常 80% 用到的是 List、Set、Map 这三大件。本章带你彻底掌握。
1. 集合框架全景
Java 集合主要分两大阵营:
- Collection 接口:存一组单值。子接口有
List(有序可重复)、Set(无序不重复)、Queue(队列)。 - Map 接口:存键值对,独立于 Collection。
常用实现类:ArrayList、LinkedList、HashSet、TreeSet、HashMap、TreeMap、LinkedHashMap。它们都用了泛型(<Type>)指定元素类型。
2. List:有序可重复
List 是有序(按插入顺序)、可重复、有索引的集合。最常用 ArrayList(基于数组,查快、尾部增删快)。
import java.util.*;
public class ListDemo {
public static void main(String[] args) {
// ArrayList:基于数组,查快,尾部增删快(最常用)
List<String> names = new ArrayList<>();
// 添加元素
names.add("小明");
names.add("小红");
names.add("小刚");
names.add("小明"); // List 允许重复
System.out.println(names); // [小明, 小红, 小刚, 小明]
// 按索引访问(O(1))
System.out.println(names.get(0)); // 小明
// 在指定位置插入
names.add(1, "小李");
System.out.println(names); // [小明, 小李, 小红, 小刚, 小明]
// 修改元素
names.set(0, "张三");
System.out.println(names.get(0)); // 张三
// 删除元素
names.remove("小明"); // 删除第一个匹配
names.remove(0); // 按索引删
System.out.println(names);
// 大小
System.out.println(names.size()); // 3
System.out.println(names.contains("小红")); // true
System.out.println(names.isEmpty()); // false
}
}ArrayList vs LinkedList:
- ArrayList:基于数组,随机访问 O(1),尾部增 O(1) 摊还,中间插删 O(n)。99% 用这个。
- LinkedList:基于双向链表,头尾增删 O(1),随机访问 O(n)。实际很少用,只有频繁头尾操作才考虑。
3. Set:不重复集合
Set 是不重复的集合,常用于去重、判断成员资格(contains)。常用 HashSet:
import java.util.*;
public class SetDemo {
public static void main(String[] args) {
// Set:不重复的集合(没有索引)
Set<String> unique = new HashSet<>();
unique.add("苹果");
unique.add("香蕉");
unique.add("苹果"); // 重复添加无效
unique.add("橘子");
System.out.println(unique); // 顺序不保证(哈希顺序)
System.out.println(unique.size()); // 3
// 经典应用:数组去重
List<Integer> nums = Arrays.asList(1, 2, 2, 3, 3, 3, 4);
Set<Integer> set = new HashSet<>(nums);
System.out.println(set); // [1, 2, 3, 4]
System.out.println(set.contains(3)); // true
// TreeSet:按自然顺序(字典序/数值升序)
Set<String> sorted = new TreeSet<>();
sorted.add("banana");
sorted.add("apple");
sorted.add("cherry");
System.out.println(sorted); // [apple, banana, cherry](已排序)
// LinkedHashSet:保留插入顺序
Set<String> linked = new LinkedHashSet<>();
linked.add("c");
linked.add("a");
linked.add("b");
System.out.println(linked); // [c, a, b](插入顺序)
}
}- HashSet:基于哈希表,查找 O(1),无序。最常用。
- TreeSet:基于红黑树,自动排序,查找 O(log n)。
- LinkedHashSet:保留插入顺序。
4. Map:键值对
Map 存键值对(key-value),key 不重复。最常用 HashMap(哈希表实现,查找 O(1)):
import java.util.*;
public class MapDemo {
public static void main(String[] args) {
// HashMap:键值对,键不重复,O(1) 查找(最常用)
Map<String, Integer> ages = new HashMap<>();
ages.put("小明", 20);
ages.put("小红", 22);
ages.put("小刚", 21);
// 按 key 取值
System.out.println(ages.get("小明")); // 20
// put 同一个 key 会覆盖
ages.put("小明", 25);
System.out.println(ages.get("小明")); // 25
// 是否包含 key / value
System.out.println(ages.containsKey("小红")); // true
System.out.println(ages.containsValue(22)); // true
// size / remove
System.out.println(ages.size()); // 3
ages.remove("小刚");
// 三种遍历方式
// 1. 遍历 entrySet(最常用,推荐)
for (Map.Entry<String, Integer> e : ages.entrySet()) {
System.out.println(e.getKey() + " => " + e.getValue());
}
// 2. 只遍历 key
for (String name : ages.keySet()) {
System.out.println(name);
}
// 3. 只遍历 value
for (int age : ages.values()) {
System.out.println(age);
}
// getOrDefault:避免 null
int age = ages.getOrDefault("小张", -1);
System.out.println(age); // -1
}
}- HashMap:无序,O(1) 查找,99% 用这个。允许 null key/value。
- TreeMap:按 key 排序(红黑树),O(log n)。
- LinkedHashMap:保留插入顺序,或按访问顺序(可做 LRU 缓存)。
- ConcurrentHashMap:线程安全的 HashMap(多线程必用)。
遍历 Map 推荐 entrySet——一次拿到 key+value,性能最好。遍历 key 用 keySet,遍历 value 用 values。
5. 泛型(Generics)
尖括号 <Type> 是泛型:指定集合只能放什么类型。这是 Java 5 引入的类型安全机制:
import java.util.*;
// 自定义泛型类
class Box<T> {
private T item;
public void set(T item) { this.item = item; }
public T get() { return item; }
}
public class GenericDemo {
public static void main(String[] args) {
// 泛型:类型参数化,编译期检查类型安全
List<String> strings = new ArrayList<>();
strings.add("hi");
// strings.add(100); // ❌ 编译报错:类型不匹配
String s = strings.get(0); // 不用强转
System.out.println(s);
// 自定义泛型类的使用
Box<String> strBox = new Box<>();
strBox.set("hello");
System.out.println(strBox.get());
Box<Integer> intBox = new Box<>();
intBox.set(42);
System.out.println(intBox.get());
// ⚠️ 泛型不支持基本类型,要用包装类
// List<int> wrong; // ❌
List<Integer> right; // ✅
}
}泛型的好处:
- 编译期类型检查:放错类型编译报错,而不是运行时 ClassCastException。
- 省去强转:取出来直接是 String,不用
(String) obj。 - 代码复用:一个泛型类/方法可以处理多种类型。
6. 遍历:Iterator 与 forEach
import java.util.*;
public class IterDemo {
public static void main(String[] args) {
List<String> names = new ArrayList<>(Arrays.asList("a", "b", "c", "d"));
// 1. 增强 for(最简洁)
for (String n : names) {
System.out.print(n + " ");
}
System.out.println();
// 2. Iterator(遍历时需要删除元素,必须用 Iterator)
Iterator<String> it = names.iterator();
while (it.hasNext()) {
String n = it.next();
if (n.equals("b")) {
it.remove(); // ✅ 安全删除
}
}
System.out.println(names); // [a, c, d]
// ⚠️ 增强 for 里直接 list.remove() 会抛 ConcurrentModificationException
// for (String n : names) {
// if (n.equals("c")) names.remove(n); // ❌
// }
// 3. Java 8+ forEach + lambda
names.forEach(n -> System.out.print(n + " "));
System.out.println();
// 4. Java 8+ Stream(函数式数据处理)
names.stream()
.filter(n -> n.length() == 1)
.map(String::toUpperCase)
.forEach(System.out::print);
}
}新手雷区:增强 for 循环里直接 list.remove() 会抛 ConcurrentModificationException。遍历时删除必须用 Iterator.remove()。
7. Collections 工具类与不可变集合
java.util.Collections(注意带 s,是工具类,不是 Collection 接口)封装了一堆静态方法:
import java.util.*;
public class CollectionsTool {
public static void main(String[] args) {
List<Integer> nums = new ArrayList<>(Arrays.asList(5, 2, 8, 1, 9));
// Collections 工具类(注意:不是 Collection 接口!)
Collections.sort(nums); // 排序(升序)
System.out.println(nums); // [1, 2, 5, 8, 9]
Collections.reverse(nums); // 反转
System.out.println(nums); // [9, 8, 5, 2, 1]
Collections.shuffle(nums); // 随机打乱
System.out.println(nums);
System.out.println(Collections.max(nums)); // 最大值
System.out.println(Collections.min(nums)); // 最小值
Collections.fill(nums, 0); // 全部填 0
System.out.println(nums); // [0, 0, 0, 0, 0]
// 不可变集合(Java 9+ List.of / Set.of / Map.of)
List<String> immutable = List.of("a", "b", "c");
// immutable.add("d"); // ❌ 抛 UnsupportedOperationException
// Arrays.asList:把数组转 List(固定大小,不能 add/remove)
List<Integer> fixed = Arrays.asList(1, 2, 3);
fixed.set(0, 99); // ✅ 能修改元素
// fixed.add(4); // ❌ UnsupportedOperation
}
}8. 集合选型速查表
| 需求 | 选什么 |
|---|---|
| 有序、可重复、按索引访问 | ArrayList |
| 不重复、快速查找 | HashSet |
| 不重复、自动排序 | TreeSet |
| 键值对、快速查找 | HashMap |
| 键值对、按 key 排序 | TreeMap |
| 多线程并发安全 | CopyOnWriteArrayList / ConcurrentHashMap |
小结
这一章你掌握了 Java 集合框架:List、Set、Map 三大件,泛型,Iterator,Collections 工具类。新手记住两个最常用的:ArrayList 存列表,HashMap 存键值对,覆盖 80% 日常需求。下一篇我们看 Java 异常处理——让程序出错也不崩。
← 上一篇 Java 抽象类与接口
下一篇 Java 异常处理 →