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() 等专用方法!


原始标题:Introduction to PCollections | Baeldung