集合选择决策树:3 秒定位你需要的集合
先问自己 3 个问题
需要什么结构?
├── 键值对(K-V)→ Map
│ 继续问:需要排序吗?
│ ├── 需要 → TreeMap
│ ├── 需要保持插入顺序 → LinkedHashMap
│ └── 不需要 → ConcurrentHashMap(并发)/ HashMap(单线程)
│
├── 唯一性(去重)→ Set
│ 继续问:需要有序吗?
│ ├── 需要排序 → TreeSet
│ ├── 需要插入顺序 → LinkedHashSet
│ └── 不需要 → HashSet
│
└── 有序可重复 → List
继续问:操作特点是什么?
├── 随机访问多(遍历/下标)→ ArrayList
├── 头尾操作多(队列/栈)→ ArrayDeque
└── 迭代中频繁增删中间元素 → LinkedListMap 家族:选型表
| 需求 | 推荐 | 原因 |
|---|---|---|
| 通用场景,单线程 | HashMap | O(1) 查找,性能最优 |
| 需要保持插入顺序 | LinkedHashMap | 内部维护双向链表 |
| 需要按键排序 | TreeMap | 红黑树,O(log n) |
| 高并发写入 | ConcurrentHashMap | CAS + synchronized |
| 缓存(自动清理过期 key) | WeakHashMap | key 无强引用时被 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 家族:选型表
| 需求 | 推荐 | 原因 |
|---|---|---|
| 通用去重 | HashSet | O(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 快 |
| 迭代中频繁增删中间 | LinkedList | O(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