1. 概述
本文将介绍 PCollections —— 一个提供 持久化、不可变集合 的 Java 库。
持久化数据结构(collections)在更新操作时不能直接修改原对象,而是返回一个包含更新结果的新对象。它们不仅不可变,还具有持久化特性 —— 修改后,集合的旧版本仍然保持不变。
PCollections 与 Java 集合框架类似且兼容,是函数式编程和并发场景下的利器。
2. 依赖配置
在项目中使用 PCollections,需添加以下依赖到 pom.xml
:
<dependency>
<groupId>org.pcollections</groupId>
<artifactId>pcollections</artifactId>
<version>2.1.2</version>
</dependency>
若使用 Gradle,则添加到 build.gradle
:
compile 'org.pcollections:pcollections:2.1.2'
最新版本可在 Maven Central 查询。
3. Map 结构 (HashPMap)
HashPMap
是持久化 Map 结构,相当于 java.util.HashMap
,用于存储非空键值对。
可通过 HashTreePMap
的静态方法创建实例:
- ✅
empty()
:创建空HashPMap
(类似HashMap
默认构造器) - ✅
singleton()
:创建单元素HashPMap
- ✅
from()
:从现有java.util.Map
创建
// 创建空 Map
HashPMap<String, String> pmap = HashTreePMap.empty();
// 创建单元素 Map
HashPMap<String, String> pmap1 = HashTreePMap.singleton("key1", "value1");
assertEquals(pmap1.size(), 1);
// 从 HashMap 创建
Map map = new HashMap();
map.put("mkey1", "mval1");
map.put("mkey2", "mval2");
HashPMap<String, String> pmap2 = HashTreePMap.from(map);
assertEquals(pmap2.size(), 2);
⚠️ 注意:虽然 HashPMap
继承了 java.util.Map
的方法,但直接调用 put()
会抛出 UnsupportedOperationException
。持久化集合的修改必须通过专用方法:
HashPMap<String, String> pmap = HashTreePMap.empty();
HashPMap<String, String> pmap0 = pmap.plus("key1", "value1");
Map map = new HashMap();
map.put("key2", "val2");
map.put("key3", "val3");
HashPMap<String, String> pmap1 = pmap0.plusAll(map);
HashPMap<String, String> pmap2 = pmap1.minus("key1");
HashPMap<String, String> pmap3 = pmap2.minusAll(map.keySet());
assertEquals(pmap0.size(), 1);
assertEquals(pmap1.size(), 3);
assertFalse(pmap2.containsKey("key1"));
assertEquals(pmap3.size(), 0);
核心方法总结:
| 操作 | 单元素 | 多元素 |
|------------|-------------|-------------|
| 添加 | plus()
| plusAll()
|
| 删除 | minus()
| minusAll()
|
4. List 结构 (TreePVector 和 ConsPStack)
TreePVector
:持久化版ArrayList
ConsPStack
:持久化版LinkedList
两者均提供相似的静态工厂方法:
- ✅
empty()
:创建空集合 - ✅
singleton()
:创建单元素集合 - ✅
from()
:从java.util.Collection
创建
TreePVector
操作示例:
TreePVector pVector = TreePVector.empty();
TreePVector pV1 = pVector.plus("e1");
TreePVector pV2 = pV1.plusAll(Arrays.asList("e2", "e3", "e4"));
assertEquals(1, pV1.size());
assertEquals(4, pV2.size());
TreePVector pV3 = pV2.minus("e1");
TreePVector pV4 = pV3.minusAll(Arrays.asList("e2", "e3", "e4"));
assertEquals(pV3.size(), 3);
assertEquals(pV4.size(), 0);
TreePVector pSub = pV2.subList(0, 2);
assertTrue(pSub.contains("e1") && pSub.contains("e2"));
TreePVector pVW = (TreePVector) pV2.with(0, "e10");
assertEquals(pVW.get(0), "e10");
关键特性:
- ✅ 所有修改操作(如
subList()
)均返回新对象,原对象不变 - ✅
with(index, value)
替换指定位置元素 - ✅
ConsPStack
提供相同方法集,但底层实现不同
5. Set 结构 (MapPSet)
MapPSet
是持久化版 HashSet
,通过 HashTreePSet
的静态方法创建:
MapPSet pSet = HashTreePSet.empty()
.plusAll(Arrays.asList("e1","e2","e3","e4"));
assertEquals(pSet.size(), 4);
MapPSet pSet1 = pSet.minus("e4");
assertFalse(pSet1.contains("e4"));
额外提供 OrderedPSet
—— 相当于持久化版 LinkedHashSet
,保持插入顺序。
6. 总结
PCollections 提供了与 Java 核心集合对应的持久化数据结构,其核心优势在于:
- ✅ 不可变性:避免并发修改问题
- ✅ 持久化:修改后保留历史版本
- ✅ 兼容性:与 Java 集合框架无缝协作
深入细节可查阅 PCollections Javadoc,完整代码示例见 GitHub。
踩坑提醒:直接调用 put()
等修改方法会抛异常,务必使用 plus()
/minus()
等专用方法!