1. ArrayDeque —— 更好用的队列/栈

ArrayDeque 是一个基于数组实现的双端队列,既可以当 队列 也可以当 。比 LinkedList 更快更轻量。

常用 API:

  • addFirst(e) / addLast(e):从头/尾添加
  • offerFirst(e) / offerLast(e):和 add 类似,但失败时不会抛异常
  • removeFirst() / removeLast():移除并返回头/尾元素
  • pollFirst() / pollLast():移除并返回头/尾元素,失败返回 null
  • peekFirst() / peekLast():查看头/尾元素但不移除
  • push(e) / pop():栈的用法(压栈/弹栈)

例子:

ArrayDeque<String> deque = new ArrayDeque<>();
deque.addFirst("A");
deque.addLast("B");
deque.push("C"); // 相当于 addFirst

System.out.println(deque); // [C, A, B]

System.out.println(deque.pop());   // C
System.out.println(deque.pollLast()); // B

总结:用 ArrayDeque 替代 StackLinkedList,性能更好。


2. HashMap —— 最常用的键值对容器

HashMap 是基于哈希表实现的键值对容器,查找、插入、删除 都是 O(1) 平均复杂度。

常用 API:

  • put(key, value):插入或更新

  • get(key):获取值

  • containsKey(key) / containsValue(value):是否包含

  • remove(key):删除

  • forEach((k,v) -> {...}):遍历

  • 现代 API(很重要!):

    • computeIfAbsent(key, k -> new ...)
    • computeIfPresent(key, (k,v) -> ...)
    • merge(key, value, (oldVal, newVal) -> ...)
    • getOrDefault(key, defaultValue)

例子:

Map<String, List<Integer>> map = new HashMap<>();

// 如果 key 不存在,就创建一个新的 ArrayList
map.computeIfAbsent("nums", k -> new ArrayList<>()).add(1);
map.computeIfAbsent("nums", k -> new ArrayList<>()).add(2);

System.out.println(map); // {nums=[1, 2]}

// 如果 key 存在,修改它的值
map.computeIfPresent("nums", (k, v) -> {
    v.add(3);
    return v;
});
System.out.println(map); // {nums=[1, 2, 3]}

// 合并值
map.merge("nums", Arrays.asList(4), (oldVal, newVal) -> {
    oldVal.addAll(newVal);
    return oldVal;
});
System.out.println(map); // {nums=[1, 2, 3, 4]}

总结:computeIfAbsent 在处理「一键多值」的场景(比如 Map<String, List>)特别好用。


3. TreeMap —— 自动排序的 Map

TreeMap 是基于 红黑树 实现的有序 Map,会按照 key 的自然顺序(或自定义 Comparator)排序。

常用 API:

  • HashMap 基本一致(put/get/forEach)

  • 额外的有序 API:

    • firstKey() / lastKey():最小/最大 key
    • higherKey(k) / lowerKey(k):比 k 大/小的最近 key
    • subMap(from, to):区间子集

例子:

TreeMap<Integer, String> treeMap = new TreeMap<>();
treeMap.put(3, "C");
treeMap.put(1, "A");
treeMap.put(2, "B");

System.out.println(treeMap); // {1=A, 2=B, 3=C}
System.out.println(treeMap.firstKey()); // 1
System.out.println(treeMap.higherKey(1)); // 2

总结:当你需要 有序的 Map,首选 TreeMap


4. HashSet —— 不重复的集合

HashSet 本质上是 HashMap 的一个特殊实现,只存 key,不存 value。
特点是 无序、不可重复

常用 API:

  • add(e):添加
  • remove(e):删除
  • contains(e):是否存在
  • forEach(e -> {...}):遍历

例子:

Set<String> set = new HashSet<>();
set.add("A");
set.add("B");
set.add("A"); // 重复元素不会加入

System.out.println(set); // [A, B]
System.out.println(set.contains("A")); // true

总结:快速去重,首选 HashSet


5. TreeSet —— 自动排序的 Set

TreeSet 是基于 TreeMap 的有序集合,元素自动排序。

常用 API:

  • HashSet 类似(add/remove/contains)

  • 排序特有:

    • first() / last():最小/最大元素
    • higher(e) / lower(e):比 e 大/小的最近元素
    • subSet(from, to):区间子集

例子:

TreeSet<Integer> treeSet = new TreeSet<>();
treeSet.add(3);
treeSet.add(1);
treeSet.add(2);

System.out.println(treeSet); // [1, 2, 3]
System.out.println(treeSet.first()); // 1
System.out.println(treeSet.higher(1)); // 2

总结:当你需要 排序+去重 的集合,用 TreeSet

6. PriorityQueue —— Java 的优先队列

PriorityQueue 是基于 堆(Heap) 实现的优先队列。它的特点是:

  • 默认是 小顶堆(最小的元素优先)
  • 插入和取出都是 O(logN)

常用 API:

  • add(e) / offer(e):添加元素
  • poll():取出并移除堆顶元素(最小/最大)
  • peek():只查看堆顶元素
  • isEmpty():是否为空

默认行为(小顶堆)

PriorityQueue<Integer> pq = new PriorityQueue<>();
pq.offer(3);
pq.offer(1);
pq.offer(2);

System.out.println(pq.poll()); // 1
System.out.println(pq.poll()); // 2
System.out.println(pq.poll()); // 3

默认是小顶堆,所以每次 poll() 都取最小的元素。


自定义排序 —— 从根本上理解 Comparator

PriorityQueueTreeSetTreeMap 都支持 自定义排序

关键点是:

  • 排序是通过 Comparator 控制的

  • Comparator 的本质就是一个函数 (a, b) -> int

    • 返回负数:a 在前
    • 返回 0:相等
    • 返回正数:b 在前

例子 1:大顶堆(最大优先)

PriorityQueue<Integer> maxHeap = new PriorityQueue<>((a, b) -> b - a);
maxHeap.offer(3);
maxHeap.offer(1);
maxHeap.offer(2);

System.out.println(maxHeap.poll()); // 3
System.out.println(maxHeap.poll()); // 2
System.out.println(maxHeap.poll()); // 1

这里 (a, b) -> b - a 实际上就是 把比较反过来,从而实现大顶堆。


例子 2:字符串长度排序

PriorityQueue<String> pq = new PriorityQueue<>(
    (a, b) -> a.length() - b.length()
);

pq.offer("apple");
pq.offer("pear");
pq.offer("banana");

System.out.println(pq.poll()); // pear (3个字母)
System.out.println(pq.poll()); // apple (5个字母)
System.out.println(pq.poll()); // banana (6个字母)

这里就按照字符串长度来排。


例子 3:TreeSet 自定义排序(避免去重导致的坑)

TreeSet<String> set = new TreeSet<>(
    (a, b) -> {
        int cmp = a.length() - b.length();
        return cmp != 0 ? cmp : a.compareTo(b);
    }
);

set.add("pear");
set.add("apple");
set.add("banana");

System.out.println(set); // [pear, apple, banana]

这里先按照长度排,如果长度相等再按字典序排。
(否则 TreeSet 会认为长度相等的元素就是同一个,导致被“去重”掉)

自定义排序的记忆法

Comparator 理解成一句话:

  • 想让小的排前面:a - b
  • 想让大的排前面:b - a
  • 想按某个属性:a.attr - b.attr
  • 想多重排序:先比一个,如果相等再比另一个

这样就不会再混淆了


写在最后

底层结构是否有序是否允许重复常用 API典型场景
ArrayDeque数组按插入顺序允许addFirst/LastpollFirst/Lastpush/pop栈/队列
HashMap哈希表无序key 不可重复put/get/removecomputeIfAbsent键值对存储
TreeMap红黑树key 有序key 不可重复firstKeyhigherKeysubMap区间查找
HashSet哈希表无序不可重复add/remove/contains去重
TreeSet红黑树有序不可重复firsthighersubSet排序+去重
PriorityQueue局部有序(堆顶最优)允许offer/poll/peek优先任务调度

本站提供的所有下载资源均来自互联网,仅提供学习交流使用,版权归原作者所有。如需商业使用,请联系原作者获得授权。 如您发现有涉嫌侵权的内容,请联系我们 邮箱:[email protected]