Java 集合框架

实际开发中处理"一组数据"远比单值多——一群用户、一组订单、键值对配置。Java 集合框架(Java Collections Framework)提供了一整套成熟的数据结构,日常 80% 用到的是 List、Set、Map 这三大件。本章带你彻底掌握。

1. 集合框架全景

Java 集合主要分两大阵营:

常用实现类: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:

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](插入顺序)
    }
}

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
    }
}

遍历 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;        // ✅
    }
}

泛型的好处:

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 异常处理

✈️💬