Java集合框架:管理数据的"超级工具箱"

5 阅读10分钟

集合框架闪亮登场!它就像是一个功能强大的"数据管理工具箱",让你轻松处理各种数据集合

1.集合框架全景图

Collection(接口)              Map(接口)
├── List(有序可重复)           ├── HashMap(最常用)
│   ├── ArrayList(数组实现)    ├── TreeMap(有序)
│   ├── LinkedList(链表实现)   └── LinkedHashMap(保持插入顺序)
│   └── Vector(线程安全)
├── Set(无序不重复)
│   ├── HashSet(最常用)
│   ├── TreeSet(有序)
│   └── LinkedHashSet(保持插入顺序)
└── Queue(队列)
    ├── PriorityQueue(优先级队列)
    └── LinkedList(也可作队列)

本篇主要重点学习以下三点

  • ArrayList - 像可扩展的数组
  • HashMap - 像字典或电话本
  • HashSet - 像数学中的集合

2.ArrayList:万能的可变数组

2.1 ArrayList基础操作

import java.util.ArrayList;
import java.util.Collections;

public class ArrayListDemo {
    public static void main(String[] args) {
        System.out.println("=== ArrayList基础操作 ===");
        
        // 1. 创建ArrayList(不用指定大小!)
        ArrayList<String> fruits = new ArrayList<>();
        
        // 2. 添加元素(自动扩容!)
        fruits.add("苹果");
        fruits.add("香蕉");
        fruits.add("橙子");
        fruits.add("葡萄");
        fruits.add("西瓜");
        System.out.println("添加后的水果列表: " + fruits);
        
        // 3. 在指定位置插入元素
        fruits.add(2, "芒果");  // 在索引2处插入
        System.out.println("插入芒果后: " + fruits);
        
        // 4. 获取元素
        String firstFruit = fruits.get(0);
        System.out.println("第一个水果: " + firstFruit);
        
        // 5. 修改元素
        fruits.set(1, "草莓");  // 把索引1的香蕉改为草莓
        System.out.println("修改后: " + fruits);
        
        // 6. 删除元素
        fruits.remove(3);  // 删除索引3的元素
        System.out.println("删除索引3后: " + fruits);
        
        fruits.remove("西瓜");  // 删除指定元素
        System.out.println("删除西瓜后: " + fruits);
        
        // 7. 获取大小
        System.out.println("现在有多少种水果?" + fruits.size() + "种");
        
        // 8. 检查是否包含某元素
        boolean hasApple = fruits.contains("苹果");
        System.out.println("有苹果吗?" + hasApple);
        
        // 9. 查找元素位置
        int index = fruits.indexOf("芒果");
        System.out.println("芒果在索引" + index + "位置");
        
        // 10. 清空列表
        fruits.clear();
        System.out.println("清空后: " + fruits);
        System.out.println("现在是空的吗?" + fruits.isEmpty());
    }
}

运行结果:

=== ArrayList基础操作 ===
添加后的水果列表: [苹果, 香蕉, 橙子, 葡萄, 西瓜]
插入芒果后: [苹果, 香蕉, 芒果, 橙子, 葡萄, 西瓜]
修改后: [苹果, 草莓, 芒果, 橙子, 葡萄, 西瓜]
删除索引3后: [苹果, 草莓, 芒果, 葡萄, 西瓜]
删除西瓜后: [苹果, 草莓, 芒果, 葡萄]
现在有多少种水果?4种
有苹果吗?true
芒果在索引2位置
清空后: []
现在是空的吗?true

2.2 ArrayList遍历和排序

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;

public class ArrayListTraversal {
    public static void main(String[] args) {
        System.out.println("=== ArrayList遍历和排序 ===");
        
        // 创建一个学生名单
        ArrayList<String> students = new ArrayList<>();
        students.add("王五");
        students.add("张三");
        students.add("李四");
        students.add("赵六");
        students.add("钱七");
        
        System.out.println("原始名单: " + students);
        
        // 1. 使用for循环遍历(知道索引时)
        System.out.println("\n1. 使用for循环遍历:");
        for (int i = 0; i < students.size(); i++) {
            System.out.println("学生" + (i + 1) + ": " + students.get(i));
        }
        
        // 2. 使用增强for循环(最常用!)
        System.out.println("\n2. 使用增强for循环:");
        for (String student : students) {
            System.out.println("学生: " + student);
        }
        
        // 3. 使用Iterator(迭代器)
        System.out.println("\n3. 使用Iterator遍历:");
        Iterator<String> iterator = students.iterator();
        while (iterator.hasNext()) {
            System.out.println("学生: " + iterator.next());
        }
        
        // 4. 排序(按字母顺序)
        System.out.println("\n4. 排序后的名单:");
        Collections.sort(students);
        System.out.println(students);
        
        // 5. 打乱顺序
        System.out.println("\n5. 随机打乱顺序:");
        Collections.shuffle(students);
        System.out.println(students);
        
        // 6. 反转顺序
        System.out.println("\n6. 反转顺序:");
        Collections.reverse(students);
        System.out.println(students);
        
        // 7. 学生成绩排序示例
        System.out.println("\n=== 学生成绩排序 ===");
        ArrayList<Integer> scores = new ArrayList<>();
        scores.add(85);
        scores.add(92);
        scores.add(78);
        scores.add(95);
        scores.add(88);
        
        System.out.println("原始成绩: " + scores);
        Collections.sort(scores);  // 升序排序
        System.out.println("升序排序: " + scores);
        Collections.sort(scores, Collections.reverseOrder());  // 降序排序
        System.out.println("降序排序: " + scores);
        
        // 8. 查找最大值和最小值
        int maxScore = Collections.max(scores);
        int minScore = Collections.min(scores);
        System.out.println("最高分: " + maxScore);
        System.out.println("最低分: " + minScore);
    }
}

2.3 综合示例:学生管理系统

import java.util.ArrayList;
import java.util.Scanner;

public class StudentManagementSystem {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        ArrayList<Student> students = new ArrayList<>();
        
        System.out.println("=== 学生管理系统 ===");
        
        boolean running = true;
        while (running) {
            System.out.println("\n请选择操作:");
            System.out.println("1. 添加学生");
            System.out.println("2. 显示所有学生");
            System.out.println("3. 查找学生");
            System.out.println("4. 删除学生");
            System.out.println("5. 更新学生信息");
            System.out.println("6. 按成绩排序");
            System.out.println("7. 退出");
            System.out.print("请输入选择 (1-7): ");
            
            int choice = scanner.nextInt();
            scanner.nextLine();  // 消耗换行符
            
            switch (choice) {
                case 1:
                    addStudent(scanner, students);
                    break;
                case 2:
                    showAllStudents(students);
                    break;
                case 3:
                    findStudent(scanner, students);
                    break;
                case 4:
                    deleteStudent(scanner, students);
                    break;
                case 5:
                    updateStudent(scanner, students);
                    break;
                case 6:
                    sortStudents(students);
                    break;
                case 7:
                    running = false;
                    System.out.println("感谢使用,再见!");
                    break;
                default:
                    System.out.println("无效选择,请重新输入!");
            }
        }
        
        scanner.close();
    }
    
    // 添加学生
    private static void addStudent(Scanner scanner, ArrayList<Student> students) {
        System.out.println("\n=== 添加学生 ===");
        
        System.out.print("请输入学号: ");
        String id = scanner.nextLine();
        
        // 检查学号是否已存在
        for (Student s : students) {
            if (s.getId().equals(id)) {
                System.out.println("学号已存在,添加失败!");
                return;
            }
        }
        
        System.out.print("请输入姓名: ");
        String name = scanner.nextLine();
        
        System.out.print("请输入年龄: ");
        int age = scanner.nextInt();
        
        System.out.print("请输入成绩: ");
        double score = scanner.nextDouble();
        scanner.nextLine();  // 消耗换行符
        
        Student student = new Student(id, name, age, score);
        students.add(student);
        
        System.out.println("学生添加成功!");
    }
    
    // 显示所有学生
    private static void showAllStudents(ArrayList<Student> students) {
        System.out.println("\n=== 所有学生信息 ===");
        
        if (students.isEmpty()) {
            System.out.println("暂无学生信息!");
            return;
        }
        
        System.out.printf("%-10s %-10s %-5s %-10s\n", 
                         "学号", "姓名", "年龄", "成绩");
        System.out.println("-".repeat(35));
        
        for (Student student : students) {
            System.out.printf("%-10s %-10s %-5d %-10.2f\n",
                            student.getId(),
                            student.getName(),
                            student.getAge(),
                            student.getScore());
        }
    }
    
    // 查找学生
    private static void findStudent(Scanner scanner, ArrayList<Student> students) {
        System.out.println("\n=== 查找学生 ===");
        System.out.print("请输入要查找的学号或姓名: ");
        String keyword = scanner.nextLine();
        
        boolean found = false;
        for (Student student : students) {
            if (student.getId().equals(keyword) || 
                student.getName().contains(keyword)) {
                System.out.println("找到学生:");
                System.out.println(student);
                found = true;
            }
        }
        
        if (!found) {
            System.out.println("未找到匹配的学生!");
        }
    }
    
    // 删除学生
    private static void deleteStudent(Scanner scanner, ArrayList<Student> students) {
        System.out.println("\n=== 删除学生 ===");
        System.out.print("请输入要删除的学号: ");
        String id = scanner.nextLine();
        
        boolean removed = false;
        for (int i = 0; i < students.size(); i++) {
            if (students.get(i).getId().equals(id)) {
                students.remove(i);
                removed = true;
                break;
            }
        }
        
        if (removed) {
            System.out.println("学生删除成功!");
        } else {
            System.out.println("未找到该学号的学生!");
        }
    }
    
    // 更新学生信息
    private static void updateStudent(Scanner scanner, ArrayList<Student> students) {
        System.out.println("\n=== 更新学生信息 ===");
        System.out.print("请输入要更新的学号: ");
        String id = scanner.nextLine();
        
        for (Student student : students) {
            if (student.getId().equals(id)) {
                System.out.println("找到学生:" + student);
                
                System.out.print("请输入新姓名(直接回车保持原值): ");
                String newName = scanner.nextLine();
                if (!newName.isEmpty()) {
                    student.setName(newName);
                }
                
                System.out.print("请输入新年龄(输入0保持原值): ");
                int newAge = scanner.nextInt();
                if (newAge > 0) {
                    student.setAge(newAge);
                }
                
                System.out.print("请输入新成绩(输入负数保持原值): ");
                double newScore = scanner.nextDouble();
                scanner.nextLine();  // 消耗换行符
                if (newScore >= 0) {
                    student.setScore(newScore);
                }
                
                System.out.println("学生信息更新成功!");
                return;
            }
        }
        
        System.out.println("未找到该学号的学生!");
    }
    
    // 按成绩排序
    private static void sortStudents(ArrayList<Student> students) {
        if (students.isEmpty()) {
            System.out.println("暂无学生信息!");
            return;
        }
        
        // 使用冒泡排序(理解原理)
        for (int i = 0; i < students.size() - 1; i++) {
            for (int j = 0; j < students.size() - 1 - i; j++) {
                if (students.get(j).getScore() < students.get(j + 1).getScore()) {
                    // 交换位置
                    Student temp = students.get(j);
                    students.set(j, students.get(j + 1));
                    students.set(j + 1, temp);
                }
            }
        }
        
        System.out.println("按成绩降序排序完成!");
        showAllStudents(students);
    }
}

// 学生类
class Student {
    private String id;
    private String name;
    private int age;
    private double score;
    
    public Student(String id, String name, int age, double score) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.score = score;
    }
    
    // Getter和Setter方法
    public String getId() { return id; }
    public String getName() { return name; }
    public int getAge() { return age; }
    public double getScore() { return score; }
    
    public void setName(String name) { this.name = name; }
    public void setAge(int age) { this.age = age; }
    public void setScore(double score) { this.score = score; }
    
    @Override
    public String toString() {
        return String.format("学号: %s, 姓名: %s, 年龄: %d, 成绩: %.2f", 
                           id, name, age, score);
    }
}

3.HashMap:键值对的"字典"

3.1 HashMap基础操作

import java.util.HashMap;
import java.util.Map;

public class HashMapDemo {
    public static void main(String[] args) {
        System.out.println("=== HashMap基础操作 ===");
        
        // 1. 创建HashMap(键-值对存储)
        HashMap<String, String> phoneBook = new HashMap<>();
        
        // 2. 添加键值对
        phoneBook.put("张三", "13800138000");
        phoneBook.put("李四", "13900139000");
        phoneBook.put("王五", "13700137000");
        phoneBook.put("赵六", "13600136000");
        
        System.out.println("电话簿: " + phoneBook);
        
        // 3. 获取值
        String phoneNumber = phoneBook.get("张三");
        System.out.println("张三的电话: " + phoneNumber);
        
        // 4. 如果键不存在,返回默认值
        String unknown = phoneBook.getOrDefault("钱七", "未知号码");
        System.out.println("钱七的电话: " + unknown);
        
        // 5. 检查是否包含键或值
        boolean hasZhangSan = phoneBook.containsKey("张三");
        boolean hasNumber = phoneBook.containsValue("13900139000");
        System.out.println("有张三吗?" + hasZhangSan);
        System.out.println("有13900139000这个号码吗?" + hasNumber);
        
        // 6. 删除键值对
        phoneBook.remove("王五");
        System.out.println("删除王五后: " + phoneBook);
        
        // 7. 修改值
        phoneBook.put("李四", "13999999999");  // 覆盖原来的值
        System.out.println("修改李四号码后: " + phoneBook);
        
        // 8. 获取大小
        System.out.println("电话簿中有 " + phoneBook.size() + " 个联系人");
        
        // 9. 获取所有键
        System.out.println("所有联系人: " + phoneBook.keySet());
        
        // 10. 获取所有值
        System.out.println("所有号码: " + phoneBook.values());
        
        // 11. 清空
        phoneBook.clear();
        System.out.println("清空后: " + phoneBook);
        System.out.println("现在是空的吗?" + phoneBook.isEmpty());
    }
}

3.2 HashMap遍历

import java.util.HashMap;
import java.util.Map;

public class HashMapTraversal {
    public static void main(String[] args) {
        System.out.println("=== HashMap遍历 ===");
        
        // 创建学生成绩表
        HashMap<String, Integer> scores = new HashMap<>();
        scores.put("张三", 85);
        scores.put("李四", 92);
        scores.put("王五", 78);
        scores.put("赵六", 95);
        scores.put("钱七", 88);
        
        System.out.println("学生成绩表: " + scores);
        
        // 1. 遍历所有键
        System.out.println("\n1. 遍历所有键:");
        for (String name : scores.keySet()) {
            System.out.println("学生: " + name);
        }
        
        // 2. 遍历所有值
        System.out.println("\n2. 遍历所有值:");
        for (int score : scores.values()) {
            System.out.println("成绩: " + score);
        }
        
        // 3. 遍历所有键值对(最常用!)
        System.out.println("\n3. 遍历所有键值对:");
        for (Map.Entry<String, Integer> entry : scores.entrySet()) {
            String name = entry.getKey();
            int score = entry.getValue();
            System.out.println(name + "的成绩是: " + score);
        }
        
        // 4. 使用forEach方法(Java 8+)
        System.out.println("\n4. 使用forEach方法:");
        scores.forEach((name, score) -> {
            System.out.println(name + " -> " + score);
        });
        
        // 5. 统计成绩
        System.out.println("\n5. 成绩统计:");
        int sum = 0;
        int max = Integer.MIN_VALUE;
        int min = Integer.MAX_VALUE;
        String topStudent = "";
        
        for (Map.Entry<String, Integer> entry : scores.entrySet()) {
            int score = entry.getValue();
            sum += score;
            
            if (score > max) {
                max = score;
                topStudent = entry.getKey();
            }
            
            if (score < min) {
                min = score;
            }
        }
        
        double average = (double) sum / scores.size();
        System.out.println("平均分: " + average);
        System.out.println("最高分: " + max + " (学生: " + topStudent + ")");
        System.out.println("最低分: " + min);
    }
}

3.3 综合示例:单词计数器

import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class WordCounter {
    public static void main(String[] args) {
        System.out.println("=== 单词计数器 ===");
        Scanner scanner = new Scanner(System.in);
        
        System.out.println("请输入一段英文(输入'END'结束):");
        
        HashMap<String, Integer> wordCount = new HashMap<>();
        
        while (true) {
            String line = scanner.nextLine();
            if (line.equals("END")) {
                break;
            }
            
            // 分割单词(简单处理,按空格分割)
            String[] words = line.split("\\s+");
            
            for (String word : words) {
                // 清理单词(去掉标点,转小写)
                word = word.toLowerCase()
                        .replaceAll("[^a-z]", "");  // 去掉非字母字符
                
                if (!word.isEmpty()) {
                    // 更新计数
                    wordCount.put(word, wordCount.getOrDefault(word, 0) + 1);
                }
            }
        }
        
        // 显示结果
        System.out.println("\n=== 单词统计结果 ===");
        System.out.println("共发现 " + wordCount.size() + " 个不同的单词");
        
        // 按出现次数排序(简单的实现)
        System.out.println("\n单词出现次数(从高到低):");
        
        // 转换为列表进行排序
        List<Map.Entry<String, Integer>> entries = new ArrayList<>(wordCount.entrySet());
        
        // 排序(按值降序)
        entries.sort((a, b) -> b.getValue() - a.getValue());
        
        // 显示前10个
        int count = 0;
        for (Map.Entry<String, Integer> entry : entries) {
            System.out.printf("%-15s: %d次\n", entry.getKey(), entry.getValue());
            count++;
            if (count >= 10) break;  // 只显示前10个
        }
        
        // 查找特定单词
        System.out.print("\n请输入要查找的单词: ");
        String searchWord = scanner.next().toLowerCase();
        
        if (wordCount.containsKey(searchWord)) {
            System.out.println(searchWord + " 出现了 " + wordCount.get(searchWord) + " 次");
        } else {
            System.out.println("未找到单词: " + searchWord);
        }
        
        scanner.close();
    }
}

4.HashSet:不重复的"集合"

import java.util.HashSet;
import java.util.TreeSet;
import java.util.LinkedHashSet;

public class HashSetDemo {
    public static void main(String[] args) {
        System.out.println("=== HashSet集合操作 ===");
        
        // 1. HashSet(无序,不重复)
        System.out.println("1. HashSet(无序不重复):");
        HashSet<String> set1 = new HashSet<>();
        set1.add("苹果");
        set1.add("香蕉");
        set1.add("橙子");
        set1.add("苹果");  // 重复,不会被添加
        set1.add("葡萄");
        
        System.out.println("水果集合: " + set1);
        System.out.println("有香蕉吗?" + set1.contains("香蕉"));
        System.out.println("集合大小: " + set1.size());
        
        // 2. 集合运算
        System.out.println("\n2. 集合运算:");
        HashSet<String> set2 = new HashSet<>();
        set2.add("香蕉");
        set2.add("葡萄");
        set2.add("西瓜");
        set2.add("芒果");
        
        System.out.println("集合A: " + set1);
        System.out.println("集合B: " + set2);
        
        // 并集
        HashSet<String> union = new HashSet<>(set1);
        union.addAll(set2);
        System.out.println("并集(A∪B): " + union);
        
        // 交集
        HashSet<String> intersection = new HashSet<>(set1);
        intersection.retainAll(set2);
        System.out.println("交集(A∩B): " + intersection);
        
        // 差集
        HashSet<String> difference = new HashSet<>(set1);
        difference.removeAll(set2);
        System.out.println("差集(A-B): " + difference);
        
        // 3. TreeSet(有序)
        System.out.println("\n3. TreeSet(自动排序):");
        TreeSet<Integer> numbers = new TreeSet<>();
        numbers.add(5);
        numbers.add(2);
        numbers.add(8);
        numbers.add(1);
        numbers.add(3);
        
        System.out.println("数字集合: " + numbers);
        System.out.println("最小的数: " + numbers.first());
        System.out.println("最大的数: " + numbers.last());
        System.out.println("大于3的最小值: " + numbers.higher(3));
        System.out.println("小于5的最大值: " + numbers.lower(5));
        
        // 4. LinkedHashSet(保持插入顺序)
        System.out.println("\n4. LinkedHashSet(保持插入顺序):");
        LinkedHashSet<String> linkedSet = new LinkedHashSet<>();
        linkedSet.add("第三");
        linkedSet.add("第一");
        linkedSet.add("第二");
        linkedSet.add("第四");
        
        System.out.println("插入顺序集合: " + linkedSet);
        
        // 5. 实际应用:抽奖系统
        System.out.println("\n5. 抽奖系统:");
        HashSet<String> participants = new HashSet<>();
        participants.add("张三");
        participants.add("李四");
        participants.add("王五");
        participants.add("赵六");
        participants.add("钱七");
        participants.add("张三");  // 重复报名,自动去重
        
        System.out.println("参与抽奖的名单: " + participants);
        System.out.println("参与人数: " + participants.size());
        
        // 转换为数组用于抽奖
        String[] participantArray = participants.toArray(new String[0]);
        
        // 模拟抽奖(随机选一个)
        if (participantArray.length > 0) {
            int luckyIndex = (int) (Math.random() * participantArray.length);
            System.out.println("恭喜 " + participantArray[luckyIndex] + " 中奖!");
        }
    }
}

5.集合框架的注意事项

5.1 泛型的重要性

import java.util.ArrayList;

public class GenericsDemo {
    public static void main(String[] args) {
        System.out.println("=== 泛型的重要性 ===");
        
        // 没有泛型的ArrayList(不推荐!)
        ArrayList list1 = new ArrayList();  // 警告:原始类型
        list1.add("字符串");
        list1.add(123);        // 可以放任何类型
        list1.add(45.67);
        
        System.out.println("混合列表: " + list1);
        
        // 问题:需要强制类型转换,容易出错
        String str = (String) list1.get(0);  // 可以
        // String str2 = (String) list1.get(1);  // 运行时错误!ClassCastException
        
        // 使用泛型的ArrayList(推荐!)
        ArrayList<String> list2 = new ArrayList<>();
        list2.add("安全的字符串");
        // list2.add(123);  // 编译错误!类型安全
        // list2.add(45.67); // 编译错误!
        
        String safeStr = list2.get(0);  // 不需要强制转换
        
        System.out.println("类型安全的列表: " + list2);
    }
}

5.2 集合的性能比较

import java.util.*;

public class PerformanceComparison {
    public static void main(String[] args) {
        System.out.println("=== 集合性能比较 ===");
        
        int elementCount = 100000;
        
        // ArrayList vs LinkedList 插入性能
        System.out.println("测试插入" + elementCount + "个元素的性能:");
        
        // ArrayList
        long start = System.currentTimeMillis();
        ArrayList<Integer> arrayList = new ArrayList<>();
        for (int i = 0; i < elementCount; i++) {
            arrayList.add(i);  // 在末尾添加,很快
        }
        long arrayListTime = System.currentTimeMillis() - start;
        
        // LinkedList
        start = System.currentTimeMillis();
        LinkedList<Integer> linkedList = new LinkedList<>();
        for (int i = 0; i < elementCount; i++) {
            linkedList.add(i);  // 在末尾添加,也很快
        }
        long linkedListTime = System.currentTimeMillis() - start;
        
        System.out.println("ArrayList插入时间: " + arrayListTime + "ms");
        System.out.println("LinkedList插入时间: " + linkedListTime + "ms");
        
        // 测试随机访问性能
        System.out.println("\n测试随机访问性能:");
        
        start = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++) {
            int index = (int) (Math.random() * elementCount);
            arrayList.get(index);  // O(1) 很快
        }
        long arrayListAccessTime = System.currentTimeMillis() - start;
        
        start = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++) {
            int index = (int) (Math.random() * elementCount);
            linkedList.get(index);  // O(n) 很慢
        }
        long linkedListAccessTime = System.currentTimeMillis() - start;
        
        System.out.println("ArrayList随机访问时间: " + arrayListAccessTime + "ms");
        System.out.println("LinkedList随机访问时间: " + linkedListAccessTime + "ms");
        
        // 总结
        System.out.println("\n=== 选择指南 ===");
        System.out.println("1. 需要频繁随机访问 → ArrayList");
        System.out.println("2. 需要频繁在中间插入/删除 → LinkedList");
        System.out.println("3. 需要快速查找键对应的值 → HashMap");
        System.out.println("4. 需要不重复元素 → HashSet");
        System.out.println("5. 需要自动排序 → TreeSet/TreeMap");
    }
}

总结:集合框架学习要点

  1. ArrayList是万能的 - 大多数情况下都够用
    • 可动态扩容
    • 快速随机访问
    • 简单易用
  2. HashMap是高效的 - 键值对查找利器
    • 快速查找(O(1))
    • 键不能重复
    • 值可以重复
  3. HashSet去重复 - 需要不重复集合时用
    • 自动去重
    • 快速判断包含
    • 集合运算方便
  4. 泛型是必须的 - 保证类型安全
    • 避免类型转换错误
    • 编译时检查类型
    • 代码更清晰