1. Обзор
В этой статье мы рассмотрим PCollections , библиотеку Java, предоставляющую постоянные, неизменяемые коллекции.
Постоянные структуры данных (коллекции) не могут быть изменены непосредственно во время операции обновления, вместо этого возвращается новый объект с результатом операции обновления. Они не только неизменяемые, но и постоянные — это означает, что после модификации предыдущие версии коллекции остаются неизменными.
PCollections аналогична платформе Java Collections и совместима с ней.
2. Зависимости
Давайте добавим следующую зависимость в наш pom.xml
, чтобы мы могли использовать PCollections в нашем проекте:
<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. Структура карты ( HashPMap
)
HashPMap
— это постоянная структура данных карты. Это аналог java.util.HashMap
, используемый для хранения ненулевых данных типа "ключ-значение".
Мы можем создать экземпляр HashPMap
, используя удобные статические методы в HashTreePMap.
Эти статические методы возвращают экземпляр HashPMap
, поддерживаемый IntTreePMap.
Статический метод empty() класса
HashTreePMap
создает пустой HashPMap
, не содержащий элементов, как при использовании конструктора по умолчанию java.util.HashMap
:
HashPMap<String, String> pmap = HashTreePMap.empty();
Есть два других статических метода, которые мы можем использовать для создания HashPMap
. Метод singleton()
создает HashPMap
только с одной записью:
HashPMap<String, String> 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<String, String> pmap2 = HashTreePMap.from(map);
assertEquals(pmap2.size(), 2);
Хотя HashPMap
наследует некоторые методы от java.util.AbstractMap
и java.util.Map
, у него есть уникальные методы.
Метод minus()
удаляет одну запись с карты, а метод minusAll()
удаляет несколько записей. Также есть методы plus()
и plusAll()
, которые добавляют одну и несколько записей соответственно:
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);
Важно отметить, что вызов put()
в pmap
вызовет исключение UnsupportedOperationException.
Поскольку объекты PCollections являются постоянными и неизменяемыми, каждая операция модификации возвращает новый экземпляр объекта ( HashPMap
).
Давайте перейдем к рассмотрению других структур данных.
4. Структура списка ( TreePVector и 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. Конечно, Javadoc PCollections дает больше информации о тонкостях библиотеки.
И, как всегда, полный код можно найти на Github .