PriorityQueue默认按自然顺序构建最小堆,仅保证poll()/peek()返回最高优先级元素,遍历不有序;底层为堆结构,要求元素可比较或提供Comparator,不线程安全。

PriorityQueue 默认按自然顺序排序,但必须元素可比较
Java 的 PriorityQueue 底层是堆结构,不保证遍历有序,只保证 poll() / peek() 返回当前优先级最高的元素。默认构造器要求元素实现 Comparable 接口,否则运行时抛出 ClassCastException。
- 基本类型包装类(如
Integer、String)天然支持,默认升序(最小堆) - 自定义类必须重写
compareTo(),或显式传入Comparator - 注意:
PriorityQueue不是线程安全的,多线程需用PriorityBlockingQueue
用 Comparator 自定义排序规则(降序/多字段/空值处理)
通过构造器传入 Comparator 是最灵活的方式,尤其适合反向排序或复杂业务逻辑。Java 8+ 可用方法引用或 lambda 简化写法。
- 降序整数:
new PriorityQueue(Comparator.reverseOrder()) - 按字符串长度排序:
new PriorityQueue((a, b) -> a.length() - b.length()) - 避免空指针:用
Comparator.nullsLast()包裹,如Comparator.nullsLast(String::compareTo) - 多字段组合:先按 status 排,再按 createTime 降序 ——
Comparator.comparing(Task::getStatus).thenComparing(Task::getCreateTime, Comparator.reverseOrder())
常见误用:遍历 PriorityQueue 得不到有序结果
PriorityQueue 的内部数组不是按优先级顺序存储的,而是满足堆性质(父节点 ≤ 子节点)。直接用增强 for 循环或 iterator() 遍历,输出顺序无意义。
- 错误示例:
PriorityQueue
pq = new PriorityQueue<>(Arrays.asList(3, 1, 4, 1, 5)); for (int x : pq) System.out.print(x + " "); // 输出可能是 1 3 4 1 5,非升序 - 正确取有序序列:反复
poll()直到为空 —— 这才是真正的优先级出队顺序 - 若需一次性获取排序后列表,应转为数组再排序:
Arrays.sort(pq.toArray(), Comparator.naturalOrder()),但失去队列语义
性能与边界注意点:offer/poll 时间复杂度和初始容量
offer() 和 poll() 均为 O(log n),但底层数组扩容成本不可忽略。默认初始容量是 11,频繁扩容会触发多次 Arrays.copyOf()。
立即学习“Java免费学习笔记(深入)”;
- 预估规模时显式指定初始容量,例如:
new PriorityQueue(1000) -
remove(Object)是O(n)操作,慎用于大堆;如需高效删除任意元素,考虑TreeSet或带索引的堆实现 - 不允许插入
null元素(除非使用允许 null 的Comparator,但极不推荐) - 注意:
PriorityQueue不是SortedSet,不自动去重,重复元素会被分别存储
实际用的时候,最容易忽略的是「遍历不等于有序」这一点——很多人调试时打印整个队列就以为逻辑错了,其实只是误解了它的设计契约。堆只要维持 top 正确,其余位置根本没义务整齐。










