集合层级(简化)
Iterable
└─ Collection
├─ List 有序、可重复(ArrayList / LinkedList)
├─ Set 无重复(HashSet / TreeSet)
└─ Queue 队列(ArrayDeque / PriorityQueue)
Map(不在 Collection 体系)
├─ HashMap
├─ LinkedHashMap
├─ TreeMap
└─ ConcurrentHashMap
List:日常 80%
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add(0, "x"); // 头插
list.get(0); // "x"
list.set(0, "y"); // 改
list.remove(0); // 按索引删
list.remove("b"); // 按元素删
list.size(); // 数量
list.contains("a");
list.indexOf("a");
list.isEmpty();
for (var s : list) { ... }
ArrayList(动态数组)几乎永远是默认选择。LinkedList 几乎从不用——除了"队列"语义(用 ArrayDeque 也更好)。
Set:去重 + 快速 contains
Set<Integer> set = new HashSet<>();
set.add(1);
set.add(1); // 不重复,无操作
set.contains(1); // O(1)
set.size(); // 1
// 有序集合
SortedSet<Integer> sorted = new TreeSet<>();
sorted.add(3); sorted.add(1); sorted.add(2);
// 遍历是 1, 2, 3
Map:键值对
Map<String, Integer> ages = new HashMap<>();
ages.put("alice", 30);
ages.put("bob", 25);
ages.get("alice"); // 30
ages.getOrDefault("nobody", 0); // 0(不存在时)
ages.containsKey("alice");
ages.containsValue(30);
ages.remove("alice");
// 遍历
for (var entry : ages.entrySet()) {
System.out.println(entry.getKey() + " = " + entry.getValue());
}
// 只键 / 只值
ages.keySet();
ages.values();
Java 9+ 不可变工厂
List<Integer> list = List.of(1, 2, 3); // 不可变
Set<String> set = Set.of("a", "b", "c");
Map<String, Integer> map = Map.of("a", 1, "b", 2);
// 大 Map
Map<String, Integer> big = Map.ofEntries(
Map.entry("a", 1),
Map.entry("b", 2),
// ...
);
list.add(4); // ❌ UnsupportedOperationException
List.of / Set.of / Map.of——不可变、不接受 null、很简洁。新代码默认用这个。
集合视图:unmodifiable
List<String> mutable = new ArrayList<>();
mutable.add("a");
List<String> readonly = Collections.unmodifiableList(mutable);
readonly.add("b"); // ❌
// 但 mutable 可以改,readonly 也跟着变
mutable.add("b");
System.out.println(readonly); // [a, b]
返回"只读视图"——底层 list 改了视图也变。要真不可变用 List.of 或 List.copyOf(mutable)。
ArrayDeque:队列 + 栈
// 队列(FIFO)
Deque<Integer> queue = new ArrayDeque<>();
queue.offer(1);
queue.offer(2);
queue.poll(); // 1(取头)
queue.peek(); // 看头不弹
// 栈(LIFO)
Deque<Integer> stack = new ArrayDeque<>();
stack.push(1);
stack.push(2);
stack.pop(); // 2
// 不要用 java.util.Stack——线程同步开销 + 设计有问题
TreeMap / TreeSet:有序
TreeMap<Integer, String> map = new TreeMap<>();
map.put(3, "c");
map.put(1, "a");
map.put(2, "b");
map.firstKey(); // 1
map.lastKey(); // 3
map.headMap(2); // {1=a}
map.tailMap(2); // {2=b, 3=c}
红黑树实现,所有操作 O(log n)。需要"按 key 排序遍历"或"范围查询"用。
LinkedHashMap:保持插入顺序
Map<String, Integer> m = new LinkedHashMap<>();
m.put("c", 3); m.put("a", 1); m.put("b", 2);
// 遍历顺序:c, a, b(按插入序)
HashMap 顺序无保证;LinkedHashMap 按插入顺序。
JDK 内部:
HashMap在小数据时碰巧有序,但不要依赖——大数据 / rehash 后变。
并发集合
import java.util.concurrent.*;
Map<String, Integer> m = new ConcurrentHashMap<>(); // 多线程友好
List<Integer> list = new CopyOnWriteArrayList<>(); // 读多写少
Queue<Integer> q = new ConcurrentLinkedQueue<>();
BlockingQueue<Integer> bq = new ArrayBlockingQueue<>(10);
多线程时永远用并发集合——不要包 synchronized 自己手写。
数组 vs List
int[] arr = new int[5]; // 基本类型数组
String[] strs = {"a", "b", "c"};
Integer[] boxed = new Integer[3]; // 包装类数组
// 转换
List<String> list = Arrays.asList(strs); // 视图(不可变长度)
List<String> mutable = new ArrayList<>(Arrays.asList(strs)); // 可变副本
String[] back = list.toArray(new String[0]);
排序
List<Integer> list = new ArrayList<>(List.of(3, 1, 4, 1, 5));
Collections.sort(list); // 自然顺序
Collections.sort(list, Comparator.reverseOrder()); // 倒序
list.sort(null); // null = 自然顺序
// 自定义
list.sort((a, b) -> b - a); // 简单 lambda
list.sort(Comparator.comparing(String::length)); // 按长度
list.sort(Comparator.comparing(User::getAge)
.thenComparing(User::getName)); // 链式
常用工具
Collections.reverse(list);
Collections.shuffle(list);
Collections.frequency(list, "a");
Collections.max(list);
Collections.min(list);
Collections.fill(list, 0);
// java.util.Arrays
Arrays.sort(arr);
Arrays.fill(arr, 0);
Arrays.copyOf(arr, 10);
Arrays.binarySearch(arr, 5); // 必须先排序
Arrays.toString(arr); // 打印
Stream 转集合(下一篇细讲)
List<Integer> doubled = list.stream()
.map(n -> n * 2)
.collect(Collectors.toList()); // 老写法
// .toList(); // Java 16+
Set<Integer> set = list.stream().collect(Collectors.toSet());
Map<String, Integer> map = users.stream()
.collect(Collectors.toMap(User::getName, User::getAge));
实战选择
| 场景 | 选 |
|---|---|
| 通用列表 | ArrayList 或 List.of(不可变) |
| 去重集合 | HashSet |
| 按 key 查 | HashMap |
| 保持顺序的 Map | LinkedHashMap |
| 按 key 排序 | TreeMap |
| 队列 / 栈 | ArrayDeque(不用 Stack) |
| 多线程读写 | ConcurrentHashMap |
| 不可变 + 简洁 | List.of / Map.of(< 10 元素) |
→ 下一篇 Stream API