1. 简介
本文将深入探讨 Apache Commons Collections 库中的 Bag 接口及其使用场景。Bag 是一种特殊的集合类型,允许存储重复元素并跟踪每个元素的出现次数。
2. Maven 依赖
使用前需添加 Maven 依赖(最新版本可从 Maven Central 获取):
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.1</version>
</dependency>
3. Bag 与标准集合的区别
简单来说,Bag 是一个能存储元素及其重复计数的集合:
public void whenAdded_thenCountIsKept() {
Bag<Integer> bag = new HashBag<>(
Arrays.asList(1, 2, 3, 3, 3, 1, 4));
assertThat(2, equalTo(bag.getCount(1)));
}
3.1. 违反集合契约的行为 ⚠️
Bag 的某些方法会违反 Java 集合标准契约。例如:
标准集合:添加已存在元素返回
true
Collection<Integer> collection = new ArrayList<>(); collection.add(1); assertThat(collection.add(1), is(true));
Bag:添加已存在元素返回
false
Bag<Integer> bag = new HashBag<>(); bag.add(1); assertThat(bag.add(1), is(not(true)));
解决方案:使用 CollectionBag
装饰器使其符合集合契约:
public void whenBagAddAPILikeCollectionAPI_thenTrue() {
Bag<Integer> bag = CollectionBag.collectionBag(new HashBag<>());
bag.add(1);
assertThat(bag.add(1), is((true)));
}
4. Bag 的实现类
4.1. HashBag
✅ 核心特性:
- 支持批量添加指定数量的元素
- 可精确删除指定数量的副本
public void givenAdd_whenCountOfElementsDefined_thenCountAreAdded() {
Bag<Integer> bag = new HashBag<>();
bag.add(1, 5); // 添加5个1
assertThat(5, equalTo(bag.getCount(1)));
}
public void givenMultipleCopies_whenRemove_allAreRemoved() {
Bag<Integer> bag = new HashBag<>(
Arrays.asList(1, 2, 3, 3, 3, 1, 4));
bag.remove(3, 1); // 删除1个3,剩余2个
assertThat(2, equalTo(bag.getCount(3)));
bag.remove(1); // 删除所有1
assertThat(0, equalTo(bag.getCount(1)));
}
4.2. TreeBag
✅ 核心特性:
- 自动排序(基于元素自然顺序或自定义比较器)
- 实现
SortedBag
接口
public void givenTree_whenDuplicateElementsAdded_thenSort() {
TreeBag<Integer> bag = new TreeBag<>(Arrays.asList(7, 5,
1, 7, 2, 3, 3, 3, 1, 4, 7));
assertThat(bag.first(), equalTo(1)); // 最小值
assertThat(bag.getCount(bag.first()), equalTo(2)); // 1出现2次
assertThat(bag.last(), equalTo(7)); // 最大值
assertThat(bag.getCount(bag.last()), equalTo(3)); // 7出现3次
}
契约兼容方案:使用 CollectionSortedBag
装饰器:
public void whenTreeAddAPILikeCollectionAPI_thenTrue() {
SortedBag<Integer> bag
= CollectionSortedBag.collectionSortedBag(new TreeBag<>());
bag.add(1);
assertThat(bag.add(1), is((true)));
}
4.3. SynchronizedSortedBag
✅ 核心特性:
- 线程安全的
SortedBag
装饰器 - 适用于并发场景
public void givenSortedBag_whenDuplicateElementsAdded_thenSort() {
SynchronizedSortedBag<Integer> bag = SynchronizedSortedBag
.synchronizedSortedBag(new TreeBag<>(
Arrays.asList(7, 5, 1, 7, 2, 3, 3, 3, 1, 4, 7)));
assertThat(bag.first(), equalTo(1));
assertThat(bag.getCount(bag.first()), equalTo(2));
assertThat(bag.last(), equalTo(7));
assertThat(bag.getCount(bag.last()), equalTo(3));
}
💡 替代方案:也可组合使用
Collections.synchronizedSortedMap()
和TreeMap
实现类似功能,但SynchronizedSortedBag
更简单直接。
5. 总结
本文系统介绍了 Apache Commons Collections 中 Bag 接口的核心实现:
- HashBag:基础实现,适合无序场景
- TreeBag:有序实现,支持自动排序
- SynchronizedSortedBag:线程安全实现
所有示例代码可在 GitHub 获取。