1. 概述
本文将深入探讨 Guava 库中的两个实用集合类:EvictingQueue 和 MinMaxPriorityQueue。
EvictingQueue
实现了环形缓冲区(Circular Buffer)概念MinMaxPriorityQueue
通过自定义Comparator
提供对最小/最大元素的常量时间访问
这两个类在特定场景下能显著提升代码效率,但使用时需注意其特殊行为,避免踩坑。
2. EvictingQueue
2.1 核心特性
EvictingQueue
是一个固定大小的队列,当队列满时:
✅ 自动移除队首元素(FIFO)
✅ 新元素直接添加到队尾
❌ 不会阻塞线程或抛出异常(与标准队列不同)
可以想象成一个环形缓冲区,新元素会覆盖最旧的数据。
2.2 基础用法
创建时必须指定最大容量:
Queue<Integer> evictingQueue = EvictingQueue.create(10);
IntStream.range(0, 10)
.forEach(evictingQueue::add);
assertThat(evictingQueue)
.containsExactly(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
2.3 满队列行为
当队列已满时添加新元素:
evictingQueue.add(100);
assertThat(evictingQueue)
.containsExactly(1, 2, 3, 4, 5, 6, 7, 8, 9, 100);
⚠️ 注意:队首元素 0
被自动移除,新元素 100
添加到队尾。
2.4 适用场景
- 高效并发程序:作为环形缓冲区实现
- 数据流处理:只需保留最新 N 条记录
- 缓存淘汰策略:简单粗暴的 FIFO 淘汰
3. MinMaxPriorityQueue
3.1 核心特性
MinMaxPriorityQueue
提供以下关键能力:
✅ 常量时间访问最小元素(peekFirst()
)
✅ 常量时间访问最大元素(peekLast()
)
✅ 基于 Comparator
的动态排序
3.2 基础用法
先定义一个测试类:
class CustomClass {
private Integer value;
// 标准构造器、getter/setter
}
创建队列并指定排序规则:
MinMaxPriorityQueue<CustomClass> queue = MinMaxPriorityQueue
.orderedBy(Comparator.comparing(CustomClass::getValue))
.maximumSize(10)
.create();
IntStream
.iterate(10, i -> i - 1)
.limit(10)
.forEach(i -> queue.add(new CustomClass(i)));
验证排序结果:
assertThat(queue.peekFirst().getValue()).isEqualTo(1); // 最小值
assertThat(queue.peekLast().getValue()).isEqualTo(10); // 最大值
3.3 满队列行为
当队列满时添加新元素:
queue.add(new CustomClass(-1));
assertThat(queue.peekFirst().getValue()).isEqualTo(-1); // 新最小值
assertThat(queue.peekLast().getValue()).isEqualTo(9); // 原最大值被移除
⚠️ 特殊规则:当添加的元素比当前最大值更大时,该元素会被直接忽略:
queue.add(new CustomClass(100));
assertThat(queue.peekFirst().getValue()).isEqualTo(-1); // 不变
assertThat(queue.peekLast().getValue()).isEqualTo(9); // 不变
因为 100
比当前最大值 9
还大,所以直接丢弃。
3.4 使用注意事项
⚠️ 关键区别:
- 标准队列:满时添加会阻塞或抛出异常
MinMaxPriorityQueue
:满时添加会自动移除最大元素(除非新元素更大)
4. 总结
4.1 核心对比
特性 | EvictingQueue | MinMaxPriorityQueue |
---|---|---|
移除策略 | FIFO(队首) | 移除最大元素 |
排序能力 | 无 | 基于 Comparator 动态排序 |
特殊操作 | 无 | 忽略比当前最大值更大的元素 |
4.2 最佳实践
✅ 使用 EvictingQueue 当:需要简单高效的 FIFO 缓冲区
✅ 使用 MinMaxPriorityQueue 当:需要快速访问极值且容量有限
⚠️ 共同注意:添加元素可能导致现有元素被移除,与标准队列行为差异巨大
4.3 代码参考
完整实现示例可在 GitHub 项目 中找到(Maven 项目,可直接导入运行)。