Skip to content

集合选择决策树:3 秒定位你需要的集合

先问自己 3 个问题

需要什么结构?
├── 键值对(K-V)→ Map
│       继续问:需要排序吗?
│           ├── 需要 → TreeMap
│           ├── 需要保持插入顺序 → LinkedHashMap
│           └── 不需要 → ConcurrentHashMap(并发)/ HashMap(单线程)

├── 唯一性(去重)→ Set
│       继续问:需要有序吗?
│           ├── 需要排序 → TreeSet
│           ├── 需要插入顺序 → LinkedHashSet
│           └── 不需要 → HashSet

└── 有序可重复 → List
        继续问:操作特点是什么?
            ├── 随机访问多(遍历/下标)→ ArrayList
            ├── 头尾操作多(队列/栈)→ ArrayDeque
            └── 迭代中频繁增删中间元素 → LinkedList

Map 家族:选型表

需求推荐原因
通用场景,单线程HashMapO(1) 查找,性能最优
需要保持插入顺序LinkedHashMap内部维护双向链表
需要按键排序TreeMap红黑树,O(log n)
高并发写入ConcurrentHashMapCAS + synchronized
缓存(自动清理过期 key)WeakHashMapkey 无强引用时被 GC
不想让外部修改Map.of(...) (JDK 9+)不可变
java
// 单线程通用 → HashMap
Map<String, Object> cache = new HashMap<>();

// 需要顺序 → LinkedHashMap
Map<String, Object> ordered = new LinkedHashMap<>();

// 需要排序 → TreeMap
Map<String, Object> sorted = new TreeMap<>();
Map<String, Object> sortedDesc = new TreeMap<>(Collections.reverseOrder());

// 高并发 → ConcurrentHashMap
Map<String, Object> concurrent = new ConcurrentHashMap<>();

Set 家族:选型表

需求推荐原因
通用去重HashSetO(1) 插入和查找
需要插入顺序LinkedHashSet维护插入顺序
需要排序TreeSet自动排序
读多写少并发CopyOnWriteArraySet读不加锁,写时复制
java
// 通用去重 → HashSet
Set<String> unique = new HashSet<>();

// 保持插入顺序去重 → LinkedHashSet
Set<String> ordered = new LinkedHashSet<>();

// 排序去重 → TreeSet
Set<String> sorted = new TreeSet<>();

// 读多写少并发 → CopyOnWriteArraySet
Set<String> cow = new CopyOnWriteArraySet<>();

List 家族:选型表

需求推荐原因
通用场景ArrayList随机访问 O(1),CPU 缓存友好
头尾操作多ArrayDeque比 LinkedList 快 4 倍
模拟栈(LIFO)ArrayDeque比 Stack 快
模拟队列(FIFO)ArrayDeque比 LinkedList 快
迭代中频繁增删中间LinkedListO(1) 增删(已知位置)
读多写少并发CopyOnWriteArrayList读不加锁
java
// 通用场景 → ArrayList
List<String> list = new ArrayList<>();

// 预知大小 → 指定初始容量避免扩容
List<String> sized = new ArrayList<>(expectedSize);

// 队列/栈 → ArrayDeque(最快)
Deque<Integer> queue = new ArrayDeque<>();
Deque<Integer> stack = new ArrayDeque<>(); // push/pop

// 频繁中间增删 → LinkedList
List<String> linked = new LinkedList<>();

// 读多写少并发 → CopyOnWriteArrayList
List<String> cow = new CopyOnWriteArrayList<>();

Queue 家族:选型表

需求推荐说明
通用队列ArrayDeque无界,性能最好
优先级队列PriorityQueue按优先级出队
高并发队列ConcurrentLinkedQueue无界,非阻塞
生产者消费者LinkedBlockingQueue可选有界,阻塞
延迟队列DelayQueue元素带过期时间
java
// 普通队列 → ArrayDeque
Deque<String> queue = new ArrayDeque<>();
queue.offer("task");

// 优先队列 → PriorityQueue
Queue<Integer> pq = new PriorityQueue<>();
pq.offer(3);
pq.offer(1);
pq.offer(2);
System.out.println(pq.poll()); // 1(最小)

// 有界阻塞队列 → LinkedBlockingQueue
BlockingQueue<Task> tasks = new LinkedBlockingQueue<>(100);

选型实战:5 个常见场景

场景 1:用户缓存,按 ID 查找

java
// HashMap,O(1) 查找
Map<Long, User> userCache = new HashMap<>();

// 或者用 ConcurrentHashMap(如果缓存会被多线程更新)
ConcurrentHashMap<Long, User> userCache = new ConcurrentHashMap<>();

场景 2:排行榜,按分数排序

java
// TreeMap 按分数降序
NavigableMap<Integer, String> leaderboard =
    new TreeMap<>(Collections.reverseOrder());

leaderboard.put(95, "张三");
leaderboard.put(100, "李四");
leaderboard.put(88, "王五");

String topPlayer = leaderboard.firstEntry().getValue(); // 李四

场景 3:去重 + 保持插入顺序

java
// LinkedHashSet
List<String> allTags = Arrays.asList("Java", "Python", "Java", "Go", "Python");
List<String> unique = new ArrayList<>(new LinkedHashSet<>(allTags));
// [Java, Python, Go]

场景 4:词频统计

java
// HashMap + computeIfAbsent
Map<String, Integer> wordCount = new HashMap<>();
for (String word : text.split("\\s+")) {
    wordCount.merge(word, 1, Integer::sum);
}

场景 5:配置表,按 key 排序遍历

java
// TreeMap 自动按键排序
Map<String, String> config = new TreeMap<>();
config.put("zookeeper", "localhost:2181");
config.put("redis", "localhost:6379");
config.put("mysql", "localhost:3306");

// 按字典序遍历:mysql → redis → zookeeper
config.forEach((k, v) -> System.out.println(k + " = " + v));

避坑指南

误区正确做法
「LinkedList 增删快,所以比 ArrayList 快」只有已知位置的增删才是 O(1),随机增删反而更慢(需要 O(n) 查找)
「Hashtable 是线程安全的,所以用 Hashtable」线程安全不等于高性能,ConcurrentHashMap 快 5-10 倍
「Stack 是栈的标准实现」Stack 继承 Vector 已过时,用 ArrayDeque 作为栈
「Arrays.asList 得到的列表可以随便增删」asList 返回的是固定大小列表,增删抛异常
「Collections.synchronizedList 很安全,可以并发用」所有操作都加锁,高并发下性能很差

一句话总结

Map:HashMap 走天下,需要顺序用 LinkedHashMap,需要排序用 TreeMap,高并发用 ConcurrentHashMap
Set:HashSet 通用,需要顺序用 LinkedHashSet,需要排序用 TreeSet
List:ArrayList 通用,队列/栈用 ArrayDeque,迭代中频繁增删中间元素才用 LinkedList

相关链接

基于 VitePress 构建