Introdução ao PCollections
1. Visão geral
Neste artigo, estaremos olhando paraPCollections, aJava library providing persistent, immutable collections.
Persistent data estruturas (coleções) não podem ser modificadas diretamente durante a operação de atualização, em vez disso, um novo objeto com o resultado da operação de atualização é retornado. Eles não são apenas imutáveis, mas também persistentes - o que significa queafter modification is performed, previous versions of the collection remain unchanged.
PCollections é análogo e compatível com a estrutura Java Collections.
2. Dependências
Vamos adicionar a seguinte dependência ao nossopom.xml para usarmos PCollections em nosso projeto:
org.pcollections
pcollections
2.1.2
Se nosso projeto for baseado em Gradle, podemos adicionar o mesmo artefato ao nosso arquivobuild.gradle:
compile 'org.pcollections:pcollections:2.1.2'
A versão mais recente pode ser encontrada emMaven Central.
3. Estrutura do mapa (HashPMap)
HashPMap é uma estrutura de dados de mapa persistente. É o análogo parajava.util.HashMap usado para armazenar dados de valor-chave não nulos.
Podemos instanciarHashPMap usando métodos estáticos convenientes emHashTreePMap. Esses métodos estáticos retornam uma instânciaHashPMap que é apoiada por umIntTreePMap.
O métodoempty() estático da classeHashTreePMap cria umHashPMap vazio que não tem elementos - exatamente como usar o construtor padrão dejava.util.HashMap:
HashPMap pmap = HashTreePMap.empty();
Existem dois outros métodos estáticos que podemos usar para criarHashPMap. O métodosingleton() cria umHashPMap com apenas uma entrada:
HashPMap pmap1 = HashTreePMap.singleton("key1", "value1");
assertEquals(pmap1.size(), 1);
O métodofrom() cria umHashPMap a partir de uma instânciajava.util.HashMap existente (e outras implementaçõesjava.util.Map):
Map map = new HashMap();
map.put("mkey1", "mval1");
map.put("mkey2", "mval2");
HashPMap pmap2 = HashTreePMap.from(map);
assertEquals(pmap2.size(), 2);
EmboraHashPMap herde alguns dos métodos dejava.util.AbstractMapejava.util.Map, ele possui métodos que são exclusivos dele.
O métodominus() remove uma única entrada do mapa, enquanto o métodominusAll() remove várias entradas. Existem também os métodosplus() eplusAll() que adicionam entradas únicas e múltiplas, respectivamente:
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);
É importante observar que chamarput() empmap lançará umUnsupportedOperationException. Como os objetos PCollections são persistentes e imutáveis, cada operação de modificação retorna uma nova instância de um objeto (HashPMap) .
Vamos ver outras estruturas de dados.
4. Estrutura da lista (TreePVector and ConsPStack)
TreePVector é um análogo persistente dejava.util.ArrayList enquantoConsPStack é o análogo dejava.util.LinkedList. TreePVector eConsPStack têm métodos estáticos convenientes para criar novas instâncias - assim comoHashPMap.
O métodoempty() cria umTreePVector vazio, enquanto o métodosingleton() cria umTreePVector com apenas um elemento. Também existe o métodofrom() que pode ser usado para criar uma instância deTreePVector a partir de qualquerjava.util.Collection.
ConsPStack possui métodos estáticos com o mesmo nome que alcançam o mesmo objetivo.
TreePVector possui métodos para manipulá-lo. Possui os métodosminus()eminusAll() para remoção de elemento (s); oplus(), eplusAll() para adição de elemento (s).
Owith() é usado para substituir um elemento em um índice especificado e osubList() obtém um intervalo de elementos da coleção.
Esses métodos também estão disponíveis emConsPStack.
Vamos considerar o seguinte snippet de código que exemplifica os métodos mencionados acima:
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");
No fragmento de código acima,pSub é outro objetoTreePVector e é independente depV2. Como pode ser observado,pV2 não foi alterado pela operaçãosubList(); em vez disso, um novo objetoTreePVector foi criado e preenchido com elementos depV2 do índice 0 a 2.
É isso que significa imutabilidade e é o que acontece com todos os métodos de modificação do PCollections.
5. Estrutura do conjunto (MapPSet)
MapPSet é persistente, baseado no mapa, análogo dejava.util.HashSet. Ele pode ser convenientemente instanciado por métodos estáticos deHashTreePSet –empty(),from()esingleton(). Eles funcionam da mesma maneira que explicada nos exemplos anteriores.
MapPSet tem os métodosplus(),plusAll(),minus()eminusAll() para manipular os dados do conjunto. Além disso, ele herda métodos dejava.util.Set,java.util.AbstractCollectionejava.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"));
Finalmente, há tambémOrderedPSet - que mantém a ordem de inserção dos elementos, assim comojava.util.LinkedHashSet.
6. Conclusão
Concluindo, neste rápido tutorial, exploramos o PCollections - as estruturas de dados persistentes que são análogas às coleções principais que temos disponíveis em Java. Obviamente, as PCollectionsJavadoc fornecem mais informações sobre as complexidades da biblioteca.
E, como sempre, o código completo pode ser encontradoover on Github.