1. 概述

本文将深入探讨 Guava 库中的两个实用集合类:EvictingQueueMinMaxPriorityQueue

  • 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 项目,可直接导入运行)。


原始标题:Guide to Guava MinMaxPriorityQueue and EvictingQueue