Введение в PCollections

Введение в PCollections

1. обзор

В этой статье мы рассмотримPCollections, aJava library providing persistent, immutable collections.

Структуры (коллекции)Persistent data не могут быть изменены непосредственно во время операции обновления, вместо этого возвращается новый объект с результатом операции обновления. Они не только неизменяемы, но и постоянны - это означает, чтоafter modification is performed, previous versions of the collection remain unchanged.

PCollections аналогична и совместима с платформой Java Collections.

2. зависимости

Давайте добавим следующую зависимость к нашемуpom.xml, чтобы мы могли использовать PCollections в нашем проекте:


    org.pcollections
    pcollections
    2.1.2

Если наш проект основан на Gradle, мы можем добавить тот же артефакт в наш файлbuild.gradle:

compile 'org.pcollections:pcollections:2.1.2'

Последнюю версию можно найти наMaven Central.

3. Структура карты (HashPMap)

HashPMap - это постоянная структура данных карты. Это аналогjava.util.HashMap, используемый для хранения ненулевых данных типа ключ-значение.

Мы можем создать экземплярHashPMap, используя удобные статические методы вHashTreePMap.. Эти статические методы возвращают экземплярHashPMap, поддерживаемыйIntTreePMap.

Статический методempty() классаHashTreePMap создает пустойHashPMap без элементов - точно так же, как при использовании конструктора по умолчаниюjava.util.HashMap:

HashPMap pmap = HashTreePMap.empty();

Есть два других статических метода, которые мы можем использовать для созданияHashPMap. Методsingleton() создаетHashPMap только с одной записью:

HashPMap pmap1 = HashTreePMap.singleton("key1", "value1");
assertEquals(pmap1.size(), 1);

Методfrom() создаетHashPMap из существующего экземпляраjava.util.HashMap (и других реализацийjava.util.Map):

Map map = new HashMap();
map.put("mkey1", "mval1");
map.put("mkey2", "mval2");

HashPMap pmap2 = HashTreePMap.from(map);
assertEquals(pmap2.size(), 2);

ХотяHashPMap наследует некоторые методы отjava.util.AbstractMap иjava.util.Map, у него есть методы, которые уникальны для него.

Методminus() удаляет одну запись с карты, а методminusAll() удаляет несколько записей. Также существуют методыplus() иplusAll(), которые добавляют одну и несколько записей соответственно:

HashPMap pmap = HashTreePMap.empty();
HashPMap pmap0 = pmap.plus("key1", "value1");

Map map = new HashMap();
map.put("key2", "val2");
map.put("key3", "val3");
HashPMap pmap1 = pmap0.plusAll(map);

HashPMap pmap2 = pmap1.minus("key1");

HashPMap pmap3 = pmap2.minusAll(map.keySet());

assertEquals(pmap0.size(), 1);
assertEquals(pmap1.size(), 3);
assertFalse(pmap2.containsKey("key1"));
assertEquals(pmap3.size(), 0);

Важно отметить, что вызовput() наpmap вызоветUnsupportedOperationException.. Поскольку объекты PCollections являются постоянными и неизменяемыми, каждая операция изменения возвращает новый экземпляр объекта (HashPMap) .

Перейдем к рассмотрению других структур данных.

4. Структура списка (TreePVector and ConsPStack)

TreePVector - постоянный аналогjava.util.ArrayList, аConsPStack - аналогjava.util.LinkedList. TreePVector иConsPStack имеют удобные статические методы для создания новых экземпляров - точно так же, какHashPMap.

Методempty() создает пустойTreePVector, а методsingleton() создаетTreePVector только с одним элементом. Также существует методfrom(), который можно использовать для создания экземпляраTreePVector из любогоjava.util.Collection.

ConsPStack имеет статические методы с тем же именем, которые достигают той же цели.

TreePVector имеет методы для управления этим. У него есть методыminus() иminusAll() для удаления элемента (ов); plus() иplusAll() для добавления элемента (ов).

with() используется для замены элемента по указанному индексу, аsubList() получает диапазон элементов из коллекции.

Эти методы также доступны вConsPStack.

Давайте рассмотрим следующий фрагмент кода, который иллюстрирует упомянутые выше методы:

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");

В приведенном выше фрагменте кодаpSub является еще одним объектомTreePVector и не зависит отpV2. Как можно видеть,pV2 не был изменен операциейsubList(); скорее был создан новый объектTreePVector и заполнен элементамиpV2 от индекса 0 до 2.

Это то, что подразумевается под неизменностью, и то, что происходит со всеми модифицирующими методами PCollections.

5. Установить структуру (MapPSet)

MapPSet - это постоянный аналогjava.util.HashSet с поддержкой сопоставления. Его можно удобно создать статическими методамиHashTreePSet –empty(),from() иsingleton(). Они функционируют так же, как описано в предыдущих примерах.

MapPSet имеет методыplus(),plusAll(),minus() иminusAll() для управления данными набора. Кроме того, он наследует методы отjava.util.Set,java.util.AbstractCollection иjava.util.AbstractSet:

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, который поддерживает порядок вставки элементов точно так же, какjava.util.LinkedHashSet.

6. Заключение

В заключение, в этом кратком руководстве мы изучили PCollections - постоянные структуры данных, которые аналогичны базовым коллекциям, которые мы имеем в Java. Конечно, PCollectionsJavadoc дает больше информации о тонкостях библиотеки.

И, как всегда, полный код можно найтиover on Github.