Carte des primitives à Java

1. Vue d'ensemble

Dans ce didacticiel, nous allons apprendre à construire une carte avec des clés et des valeurs primitives.

Comme nous le savons, les Java Map s de base ne permettent pas le stockage de clés ou de valeurs primitives. C'est pourquoi nous allons introduire des bibliothèques tierces externes qui fournissent des implémentations de carte primitives.

2. Collections Eclipse

Eclipse Collections est un framework de collecte hautes performances pour Java . Il fournit des implémentations améliorées ainsi que des structures de données supplémentaires, y compris plusieurs collections primitives.

2.1. Cartes mutables et immuables

Créons une carte vide où les clés et les valeurs sont des int primitifs . Pour cela, nous utiliserons la classe d'usine IntIntMaps :

MutableIntIntMap mutableIntIntMap = IntIntMaps.mutable.empty();

La classe d'usine IntIntMaps est le moyen le plus pratique de créer des cartes primitives . Cela nous permet de créer des instances à la fois mutables et immuables du type de carte souhaité. Dans notre exemple, nous avons créé l'instance mutable d' IntIntMap . De même, nous pouvons créer une instance immuable en remplaçant simplement le IntIntMaps.mutable appel usine statique avec IntIntMaps.immutable :

ImmutableIntIntMap immutableIntIntMap = IntIntMaps.immutable.empty();

Alors, ajoutons une paire clé / valeur à notre carte mutable:

mutableIntIntMap.addToValue(1, 1);

De même, nous pouvons créer des cartes mixtes avec des paires clé-valeur de type référence et primitive. Créons une carte avec des clés String et des valeurs doubles :

MutableObjectDoubleMap dObject = ObjectDoubleMaps.mutable.empty();

Ici, nous avons utilisé la classe d'usine ObjectDoubleMaps pour créer une instance mutable pour MutableObjectDoubleMap .

Ajoutons maintenant quelques entrées:

dObject.addToValue("price", 150.5); dObject.addToValue("quality", 4.4); dObject.addToValue("stability", 0.8);

2.2. Une arborescence API primitive

Dans les collections Eclipse, il existe une interface de base appelée PrimitiveIterable. Il s'agit de l'interface de base pour chacun des conteneurs primitifs de la bibliothèque. Tous sont nommés PrimitiveTypeIterable , où PrimitiveType peut être Int, Long , Short , Byte , Char , Float , Double ou Boolean .

Toutes ces interfaces de base, à leur tour, ont leur arbre d' implémentations XY Map , qui est divisé selon que la carte est mutable ou immuable . À titre d'exemple, pour IntIntMap , nous avons MutableIntIntMap et ImmutableIntIntMap .

Enfin, comme nous l'avons vu ci-dessus, nous avons des interfaces pour couvrir toutes sortes de combinaisons de types de clés et de valeurs pour les valeurs primitives et d'objet . Ainsi, par exemple, nous pouvons avoir IntObjectMap pour une clé primitive avec une valeur Object ou ObjectIntMap pour son cas contraire.

3. HPPC

HPPC est une bibliothèque orientée vers la haute performance et l'efficacité de la mémoire. Cela signifie que la bibliothèque a moins d'abstraction que les autres. Cependant, cela présente l'avantage d'exposer les composants internes à une manipulation utile de bas niveau. Il fournit à la fois des cartes et des décors.

3.1. Un exemple simple

Commençons par créer une carte qui a une clé int et une valeur longue . L'utilisation de ceci est assez familière:

IntLongHashMap intLongHashMap = new IntLongHashMap(); intLongHashMap.put(25, 1L); intLongHashMap.put(150, Long.MAX_VALUE); intLongHashMap.put(1, 0L); intLongHashMap.get(150);

HPPC fournit des cartes pour toutes les combinaisons de clés et de valeurs:

  • Clé primitive et valeur primitive
  • Clé primitive et valeur de type d'objet
  • Clé de type objet et valeur primitive
  • Clé et valeur de type objet

Les cartes de type objet prennent en charge les génériques:

IntObjectOpenHashMap ObjectIntOpenHashMap 

La première carte a une clé int primitive et une valeur BigDecimal . La deuxième carte a LocalDate pour ses clés et int pour ses valeurs

3.2. Hash Maps vs Scatter Maps

En raison de la façon dont les fonctions de hachage et de distribution des clés sont traditionnellement implémentées, nous pourrions avoir des collisions lors du hachage des clés. Selon la façon dont les clés sont distribuées, cela peut entraîner des problèmes de performances sur de grandes cartes. Par défaut, HPPC implémente une solution qui évite ce problème.

Cependant, il y a encore une place pour les cartes qui ont une fonction de distribution plus simple. Ceci est utile si les cartes sont utilisées comme tables de recherche ou pour le comptage, ou si elles ne nécessitent pas beaucoup d'opérations d'écriture une fois chargées . HHPC fournit des Scatter Maps pour améliorer encore plus les performances.

Toutes les classes de scatter-map conservent la même convention de dénomination que les maps, mais utilisent à la place le mot Scatter :

  • IntScatterSet
  • IntIntScatterMap
  • IntObjectScatterMap

4. Fastutil

Fastutil est une infrastructure rapide et compacte qui fournit des collections spécifiques à un type, y compris des mappes de types primitifs.

4.1. Exemple rapide

Similaire aux collections Eclipse et HPPC. Fastutil fournit également des cartes d'association de type primitive à primitive et primitive à objet.

Let's create an int to boolean map:

Int2BooleanMap int2BooleanMap = new Int2BooleanOpenHashMap();

And now, let's add some entries:

int2BooleanMap.put(1, true); int2BooleanMap.put(7, false); int2BooleanMap.put(4, true);

Then, we can retrieve values from it:

boolean value = int2BooleanMap.get(1);

4.2. In-Place Iteration

Standard JVM collections that implement the Iterable interface usually create a fresh temporary iterator object at each iteration step. With huge collections, this can create a garbage collection issue.

Fastutil provides an alternative that greatly mitigates this:

Int2FloatMap map = new Int2FloatMap(); //Add keys here for(Int2FloatMap.Entry e : Fastutil.fastIterable(map)) { //e will be reused on each iteration, so it will be only one object } 

Fastutil also provides the fastForeach method. This will take a Consumer functional interface and perform a lambda-expression for each loop:

Int2FloatMap map = new Int2FloatMap(); //Add keys here Int2FloatMaps.fastForEach(map , e -> { // e is also reused across iterations }); 

This is very similar to the standard Java foreach construct:

Int2FloatMap map = new Int2FloatMap(); //Add keys here map.forEach((key,value) -> { // use each key/value entry }); 

5. Conclusion

Dans cet article, nous avons appris à créer des cartes primitives en Java à l'aide des collections Eclipse, HPPC et Fastutil .

Comme toujours, l'exemple de code de cet article est disponible à l'adresse over sur GitHub.