Java 入门教程(八):集合框架
1734 字
9 分钟
Java 入门教程(八):集合框架
- 1Java 入门教程(一):JDK、IDEA 与第一个程序
- 2Java 入门教程(二):语法基础与运算符
- 3Java 入门教程(三):流程控制
- 4Java 入门教程(四):方法与数组
- 5Java 入门教程(五):面向对象(上)——类与封装
- 6Java 入门教程(六):面向对象(下)——继承、多态与接口
- 7Java 入门教程(七):核心类库——String、包装类与常用工具
- 8Java 入门教程(八):集合框架本文
- 9Java 入门教程(九):异常处理
- 10Java 入门教程(十):文件 IO 与 NIO
- 11Java 入门教程(十一):多线程与 Lambda
- 12Java 入门教程(十二):Stream API 与综合实战
本篇目标
数组定长,集合(Collection)动态——Java 集合框架是日常开发的绝对主力(前几篇已偷偷用过 ArrayList)。本篇系统讲透 List/Set/Map 三大体系与排序方案。
一、集合体系全景
Collection(接口)├── List 有序可重复│ ├── ArrayList 动态数组(默认选择)│ └── LinkedList 双向链表├── Set 不可重复│ ├── HashSet 哈希(最快,无序)│ ├── LinkedHashSet 哈希 + 保插入序│ └── TreeSet 红黑树(自动排序)└── Queue 队列(了解)
Map(接口,独立于 Collection)├── HashMap 哈希键值对(默认选择)├── LinkedHashMap 保插入序└── TreeMap 按键排序泛型 <T>:集合声明元素类型,编译期防类型错误——List<String> 只能装 String。
二、List
ArrayList(默认选择)
import java.util.ArrayList;import java.util.List;
List<String> langs = new ArrayList<>();
// —— 增 ——langs.add("Java"); // 尾部追加langs.add(0, "C++"); // 指定位置(O(n))langs.addAll(List.of("Python", "Go")); // 批量
// —— 删 ——langs.remove("Go"); // 按对象删第一个langs.remove(0); // 按下标删(返回被删元素)langs.removeIf(s -> s.startsWith("P")); // 条件删除(Java 8+)
// —— 改查 ——langs.set(0, "Java17");String first = langs.get(0); // O(1) 随机访问System.out.println(langs.contains("C++"));System.out.println(langs.indexOf("Java"));System.out.println(langs.size());System.out.println(langs.isEmpty());
// —— 遍历 ——for (String lang : langs) { } // 增强 forfor (int i = 0; i < langs.size(); i++) { } // 下标langs.forEach(s -> System.out.println(s)); // 函数式
// —— 不可变集合(Java 9+)——List<String> frozen = List.of("a", "b"); // 不可增删改!ArrayList vs LinkedList
| ArrayList | LinkedList | |
|---|---|---|
| 随机访问 | O(1) | O(n) |
| 尾部增删 | 均摊 O(1) | O(1) |
| 中间增删 | O(n) | 定位 O(n) + 修改 O(1) |
| 实践建议 | 99% 场景 | 极少胜出 |
安全删除:ConcurrentModificationException
List<Integer> nums = new ArrayList<>(List.of(1, 2, 3, 4));
// ❌ 遍历中直接 remove → ConcurrentModificationException(fail-fast)// for (Integer n : nums) { if (n % 2 == 0) nums.remove(n); }
// ✅ 三种正确姿势nums.removeIf(n -> n % 2 == 0); // ① 条件删除(最简)for (Iterator<Integer> it = nums.iterator(); it.hasNext(); ) { // ② 迭代器 if (it.next() % 2 == 0) it.remove();}// ③ 倒序下标循环(正序会跳元素)三、Set
import java.util.*;
// HashSet:去重最快(依赖 hashCode/equals)Set<String> tags = new HashSet<>();tags.add("java");tags.add("python");tags.add("java"); // 重复添加被忽略System.out.println(tags.size()); // 2System.out.println(tags.contains("java")); // true
// 列表去重一行流List<Integer> dup = new ArrayList<>(List.of(3, 1, 3, 2, 1));Set<Integer> uniq = new LinkedHashSet<>(dup); // 保序去重System.out.println(uniq); // [3, 1, 2]
// TreeSet:自动排序Set<Integer> sorted = new TreeSet<>(List.of(5, 1, 4));System.out.println(sorted); // [1, 4, 5]// 首尾与范围TreeSet<Integer> ts = new TreeSet<>(List.of(1, 3, 5, 7, 9));System.out.println(ts.first() + " " + ts.last()); // 1 9System.out.println(ts.headSet(5)); // [1, 3](小于5)System.out.println(ts.tailSet(5)); // [5, 7, 9]System.out.println(ts.floor(6)); // 5(≤6 的最大)自定义对象入 HashSet/HashMap 的前提:正确重写 hashCode + equals(第六篇)——忘了重写,“相等”的两个对象会被当成两个存两份。
四、Map
HashMap(默认选择)
import java.util.HashMap;import java.util.Map;
Map<String, Integer> ages = new HashMap<>();
// —— 增改 ——ages.put("小明", 18); // 不存在则增,存在则改(返回旧值!)ages.putIfAbsent("小红", 17); // 不存在才放ages.put("小明", 19); // 覆盖为 19
// —— 查 ——int age = ages.get("小明"); // 19Integer none = ages.get("不存在"); // nullint def = ages.getOrDefault("不存在", 0); // 0(推荐!防 null)
System.out.println(ages.containsKey("小明"));System.out.println(ages.containsValue(19));
// —— 删 ——ages.remove("小红");ages.remove("小明", 19); // 键值都对上才删
// —— 遍历三式 ——for (String key : ages.keySet()) { } // 遍历键for (Integer val : ages.values()) { } // 遍历值for (Map.Entry<String, Integer> e : ages.entrySet()) // 键值对(最常用) System.out.println(e.getKey() + " = " + e.getValue());
// Java 8+ 函数式遍历ages.forEach((k, v) -> System.out.println(k + ":" + v));
// —— 统计利器 ——ages.merge("小明", 1, Integer::sum); // 计数器模式:旧值+1System.out.println(ages); // {小明=20}ages.computeIfAbsent("列表", k -> new java.util.ArrayList<String>()) .add("元素"); // 多值 Map 的构建块merge 计数器(词频统计一行核心)
String[] words = "the quick the lazy the dog".split(" ");Map<String, Integer> freq = new HashMap<>();for (String w : words) { freq.merge(w, 1, Integer::sum); // 没有则放1,有则 +1}System.out.println(freq); // {the=3, quick=1, lazy=1, dog=1}HashMap vs TreeMap vs LinkedHashMap
| HashMap | LinkedHashMap | TreeMap | |
|---|---|---|---|
| 查找 | O(1) | O(1) | O(log n) |
| 顺序 | 无 | 插入序 | 键排序 |
| 场景 | 默认 | 需保序(LRU) | 范围查询/排序遍历 |
五、排序:Comparable 与 Comparator
Comparable:自然顺序(类自己定义)
class Student implements Comparable<Student> { String name; int score;
Student(String name, int score) { this.name = name; this.score = score; }
@Override public int compareTo(Student o) { return Integer.compare(this.score, o.score); // 升序(反过来即降序) }
@Override public String toString() { return name + ":" + score; }}Comparator:外部策略(灵活多变)
import java.util.*;
List<Student> st = new ArrayList<>(List.of( new Student("小明", 90), new Student("小红", 92), new Student("小刚", 85)));
// 策略1:按分数降序(匿名内部类老写法 → lambda 新写法)st.sort((a, b) -> b.score - a.score);st.sort(Comparator.comparingInt((Student s) -> s.score).reversed());
// 策略2:按姓名排序st.sort(Comparator.comparing(s -> s.name));
// 策略3:多级排序(分数降序,同分按姓名升序)st.sort(Comparator.comparingInt((Student s) -> s.score).reversed() .thenComparing(s -> s.name));
System.out.println(st); // [小红:92, 小明:90, 小刚:85]选择:类的”天生顺序”用 Comparable;临时/多种排序策略用 Comparator(组合万岁)。
Collections 工具类
Collections.sort(list); // = list.sort(null)Collections.reverse(list);Collections.shuffle(list); // 随机打乱Collections.max(list);Collections.frequency(list, "a"); // 出现次数Collections.swap(list, 0, 1);Collections.unmodifiableList(list); // 不可变视图六、综合案例:学生成绩管理系统
import java.util.*;import java.util.stream.Collectors;
public class ScoreSystem { record Student(String name, String clazz, int score) {} // Java 16+ 数据类
public static void main(String[] args) { List<Student> all = List.of( new Student("小明", "一班", 90), new Student("小红", "二班", 85), new Student("小刚", "一班", 92), new Student("小美", "二班", 78), new Student("小强", "一班", 66) );
// 1. 排行榜(多级排序) List<Student> rank = new ArrayList<>(all); rank.sort(Comparator.comparingInt(Student::score).reversed()); rank.forEach(s -> System.out.printf(" %s %s %d%n", s.name(), s.clazz(), s.score()));
// 2. 按班级分组 Map<String, List<Student>> byClass = new LinkedHashMap<>(); for (Student s : all) byClass.computeIfAbsent(s.clazz(), k -> new ArrayList<>()).add(s);
byClass.forEach((cls, list) -> { double avg = list.stream().mapToInt(Student::score) .average().orElse(0); System.out.printf("%s: %d人 平均%.1f%n", cls, list.size(), avg); });
// 3. 词频式统计分数段 Map<String, Integer> dist = new TreeMap<>(); for (Student s : all) { String band = s.score() >= 90 ? "90+" : s.score() >= 80 ? "80+" : s.score() >= 60 ? "60+" : "挂科"; dist.merge(band, 1, Integer::sum); } System.out.println("分数段: " + dist);
// 4. 挂科名单(stream 预告第十二篇) List<String> failed = all.stream() .filter(s -> s.score() < 60) .map(Student::name) .collect(Collectors.toList()); System.out.println("挂科: " + (failed.isEmpty() ? "无" : failed)); }}七、容器选型决策表
| 需求 | 选择 |
|---|---|
| 动态列表(默认) | ArrayList |
| 自动去重 | HashSet / 保序用 LinkedHashSet |
| 有序集合/排名 | TreeSet |
| 键值查找(默认) | HashMap |
| 键值保插入序 | LinkedHashMap |
| 键有序遍历/范围查 | TreeMap |
| 一键多值 | Map<K, List<V>> + computeIfAbsent |
| 只读常量集合 | List.of / Set.of / Map.of |
小练习
- 词频统计 Top3:按次数降序、同次数按字典序(entrySet 搬进 List 多级排序)
- 两个班级名单求:并集(去重)、交集、只在一班的人
- 用
Map<String, List<String>>实现”分组通讯录”:录入若干 (姓名, 分组),按组输出 - 模拟抽签:ArrayList 装 30 人,
Collections.shuffle后取前 5 名(TreeSet 记录已中签防重复) - 给第四篇的
merge(int[] a, int[] b)改用List<Integer>实现,对比两种容器的代码差异
本篇小结
- List 有序可重复(ArrayList 默认);Set 去重;Map 键值对
- 遍历中删除用 removeIf / 迭代器,防 fail-fast
- 自定义对象进 HashSet/HashMap:hashCode + equals 成对重写
- merge/computeIfAbsent 是计数与分组的黄金搭档
- Comparable 定天生序,Comparator 定策略序(comparing/reversed/thenComparing)
- List.of 系列做不可变集合
下一篇:异常体系——try/catch 全解与自定义异常。
本系列为 Cyber先锋社原创教程。merge 计数器 + computeIfAbsent 分组 = 集合实战双绝,务必掌握。
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!
Java 入门教程(八):集合框架
https://www.cyberpioneer.club/posts/java-tutorial-08/相关文章智能推荐
1
Java 入门教程(三):流程控制
Java 教程完整讲解 Java 分支(if/switch 语句与 switch 表达式)、三种循环、break/continue 带标签跳转、嵌套循环经典练习(九九表/质数/图形/水仙花),覆盖 Java 14+ 增强 switch 新语法。
2
Java 入门教程(四):方法与数组
Java 教程掌握 Java 方法定义与重载、可变参数、值传递本质、数组全操作(声明/遍历/工具类 Arrays/二维数组)、命令行参数与 main 签名,附数组统计与矩阵转置实战。
3
Java 入门教程(二):语法基础与运算符
Java 教程详解 Java 基本语法:注释、变量与常量、八种基本类型与类型转换规则、七类运算符、Scanner 输入进阶与 printf 格式化,配典型陷阱与对照示例。
4
Java 入门教程(一):JDK、IDEA 与第一个程序
Java 教程进入 Java 的世界:理解"一次编写,到处运行"的原理、安装 JDK 与 IDEA、解剖第一个程序的结构、掌握变量与数据类型。企业级开发语言的起点。
5
Java 入门教程(九):异常处理
Java 教程完整讲解 Java 异常体系:异常层级分类(受检/非受检)、try/catch/finally 执行规则、try-with-resources、throw 与 throws、自定义异常、异常设计最佳实践与常见误区。
随机文章随机推荐



