Introduction à PCollections

1. Vue d'ensemble

Dans cet article, nous examinerons PCollections, une bibliothèque Java fournissant des collections persistantes et immuables.

Les structures de données persistantes (collections) ne peuvent pas être modifiées directement pendant l'opération de mise à jour, mais un nouvel objet avec le résultat de l'opération de mise à jour est renvoyé. Ils ne sont pas seulement immuables mais également persistants - ce qui signifie qu'après la modification, les versions précédentes de la collection restent inchangées.

PCollections est analogue et compatible avec le framework Java Collections.

2. Dépendances

Ajoutons la dépendance suivante à notre pom.xml pour que nous puissions utiliser PCollections dans notre projet:

 org.pcollections pcollections 2.1.2 

Si notre projet est basé sur Gradle, nous pouvons ajouter le même artefact à notre fichier build.gradle :

compile 'org.pcollections:pcollections:2.1.2'

La dernière version est disponible sur Maven Central.

3. Structure de la carte ( HashPMap )

HashPMap est une structure de données de carte persistante. C'est l'analogue de java.util.HashMap utilisé pour stocker des données clé-valeur non nulles.

Nous pouvons instancier HashPMap en utilisant des méthodes statiques pratiques dans HashTreePMap. Ces méthodes statiques renvoient une instance de HashPMap qui est sauvegardée par un IntTreePMap.

La méthode static empty () de la classe HashTreePMap crée un HashPMap vide qui n'a aucun élément - tout comme l'utilisation du constructeur par défaut de java.util.HashMap :

HashPMap pmap = HashTreePMap.empty();

Il existe deux autres méthodes statiques que nous pouvons utiliser pour créer HashPMap . La méthode singleton () crée un HashPMap avec une seule entrée:

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

La méthode from () crée un HashPMap à partir d'une instance java.util.HashMap existante (et d'autres implémentations java.util.Map ):

Map map = new HashMap(); map.put("mkey1", "mval1"); map.put("mkey2", "mval2"); HashPMap pmap2 = HashTreePMap.from(map); assertEquals(pmap2.size(), 2);

Bien que HashPMap hérite de certaines des méthodes de java.util.AbstractMap et java.util.Map , il possède des méthodes qui lui sont propres.

La méthode minus () supprime une seule entrée de la carte tandis que la méthode minusAll () supprime plusieurs entrées. Il existe également les méthodes plus () et plusAll () qui ajoutent respectivement des entrées uniques et multiples:

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

Il est important de noter que l'appel de put () sur pmap lèvera une UnsupportedOperationException. Les objets PCollections étant persistants et immuables, chaque opération de modification renvoie une nouvelle instance d'un objet ( HashPMap ).

Passons à d'autres structures de données.

4. Structure de la liste ( TreePVector et ConsPStack )

TreePVector est un analogue persistant de java.util.ArrayList tandis que ConsPStack est l'analogue de java.util.LinkedList . TreePVector et ConsPStack ont des méthodes statiques pratiques pour créer de nouvelles instances - tout comme HashPMap .

La méthode empty () crée un TreePVector vide , tandis que la méthode singleton () crée un TreePVector avec un seul élément. Il existe également la méthode from () qui peut être utilisée pour créer une instance de TreePVector à partir de n'importe quel java.util.Collection .

PStack a des méthodes statiques avec le même nom qui atteignent le même objectif.

TreePVector a des méthodes pour le manipuler. Il a les méthodes minus () et minusAll () pour la suppression des éléments; le plus () et plusAll () pour l'ajout d'élément (s).

Le with () est utilisé pour remplacer un élément à un index spécifié, et le subList () obtient une plage d'éléments de la collection.

Ces méthodes sont également disponibles dans ConsPStack .

Considérons l'extrait de code suivant qui illustre les méthodes mentionnées ci-dessus:

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

Dans l'extrait de code ci-dessus, pSub est un autre objet TreePVector et est indépendant de pV2 . Comme on peut l'observer, pV2 n'a pas été modifié par l' opération subList () ; plutôt un nouvel objet TreePVector a été créé et rempli d'éléments de pV2 d'index 0 à 2.

C'est ce que l'on entend par immuabilité et c'est ce qui se passe avec toutes les méthodes de modification de PCollections.

5. Définir la structure ( MapPSet )

MapPSet est un analogue persistant, basé sur une carte, de java.util.HashSet . Il peut être facilement instancié par des méthodes statiques de HashTreePSet - empty () , from () et singleton () . Ils fonctionnent de la même manière que celle expliquée dans les exemples précédents.

MapPSet a les méthodes plus () , plusAll () , moins () et minusAll () pour manipuler les données d'ensemble. De plus, il hérite des méthodes de java.util.Set , java.util.AbstractCollection et 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"));

Enfin, il y a aussi OrderedPSet - qui maintient l'ordre d'insertion des éléments tout comme java.util.LinkedHashSet .

6. Conclusion

En conclusion, dans ce rapide didacticiel, nous avons exploré les PCollections - les structures de données persistantes qui sont analogues aux collections de base disponibles en Java. Bien entendu, le Javadoc de PCollections fournit plus d'informations sur les subtilités de la bibliothèque.

Et, comme toujours, le code complet est disponible sur Github.