Mappa delle primitive in Java

1. Panoramica

In questo tutorial impareremo come costruire una mappa con chiavi e valori primitivi.

Come sappiamo, le Java Map principali non consentono la memorizzazione di chiavi o valori primitivi. Ecco perché introdurremo alcune librerie esterne di terze parti che forniscono implementazioni di mappe primitive.

2. Collezioni Eclipse

Eclipse Collections è un framework di raccolta ad alte prestazioni per Java . Fornisce implementazioni migliorate così come alcune strutture dati aggiuntive, incluse diverse raccolte primitive.

2.1. Mappe mutevoli e immutabili

Creiamo una mappa vuota in cui sia le chiavi che i valori sono int primitivi . Per questo, useremo la classe factory IntIntMaps :

MutableIntIntMap mutableIntIntMap = IntIntMaps.mutable.empty();

La classe factory IntIntMaps è il modo più conveniente per creare mappe primitive . Ci consente di creare istanze mutabili e immutabili del tipo di mappa desiderato. Nel nostro esempio, abbiamo creato l'istanza mutabile di IntIntMap . Allo stesso modo, siamo in grado di creare un'istanza immutabile con la semplice sostituzione della IntIntMaps.mutable chiamata fabbrica statica con IntIntMaps.immutable :

ImmutableIntIntMap immutableIntIntMap = IntIntMaps.immutable.empty();

Quindi, aggiungiamo una coppia chiave e valore alla nostra mappa mutevole:

mutableIntIntMap.addToValue(1, 1);

Allo stesso modo, possiamo creare mappe miste con coppie chiave-valore di tipo primitivo e di riferimento. Creiamo una mappa con chiavi String e valori doppi :

MutableObjectDoubleMap dObject = ObjectDoubleMaps.mutable.empty();

Qui, abbiamo utilizzato la classe factory ObjectDoubleMaps per creare un'istanza mutabile per MutableObjectDoubleMap .

Ora aggiungiamo alcune voci:

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

2.2. Un albero API primitivo

In Eclipse Collections, c'è un'interfaccia di base chiamata PrimitiveIterable. Questa è l'interfaccia di base per ciascuno dei contenitori primitivi della libreria. Tutti sono denominati PrimitiveTypeIterable , dove PrimitiveType può essere Int, Long , Short , Byte , Char , Float , Double o Boolean .

Tutte queste interfacce di base, a loro volta, hanno il loro albero di implementazioni di XY Map , che è diviso in base al fatto che la mappa sia mutabile o immutabile . A titolo di esempio, per IntIntMap , abbiamo MutableIntIntMap e ImmutableIntIntMap .

Infine, come abbiamo visto sopra, abbiamo interfacce per coprire tutti i tipi di combinazioni di tipi per chiavi e valori sia per valori primitivi che per oggetti . Quindi, ad esempio, possiamo avere IntObjectMap per una chiave primitiva con un valore Object o ObjectIntMap per il suo caso opposto.

3. HPPC

HPPC è una libreria orientata verso prestazioni elevate ed efficienza della memoria. Ciò significa che la libreria ha meno astrazioni rispetto ad altre. Tuttavia, questo ha il vantaggio di esporre le parti interne a utili manipolazioni di basso livello. Fornisce sia mappe che set.

3.1. Un semplice esempio

Cominciamo creando una mappa che abbia una chiave int e un valore long . L'utilizzo di questo è abbastanza familiare:

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

HPPC fornisce mappe per tutte le combinazioni di chiavi e valori:

  • Chiave primitiva e valore primitivo
  • Chiave primitiva e valore del tipo di oggetto
  • Chiave del tipo di oggetto e valore primitivo
  • Sia la chiave di tipo oggetto che il valore

Le mappe del tipo di oggetto supportano i generici:

IntObjectOpenHashMap ObjectIntOpenHashMap 

The first map has a primitive int key and a BigDecimal value. The second map has LocalDate for its keys and int for its values

3.2. Hash Maps vs Scatter Maps

Due to the way key hashing and distribution functions are traditionally implemented, we could have collisions when hashing the keys. Depending on how keys are distributed, this can lead to performance problems on huge maps. By default, HPPC implements a solution that avoids this problem.

However, there is still a place for maps that have a simpler distribution function. This is useful if the maps are used as lookup tables or for counting, or if they don't require lots of write operations once loaded. HHPC provides Scatter Maps to boost performance even more.

All the scatter-map classes maintain the same naming convention as maps, but instead use the word Scatter:

  • IntScatterSet
  • IntIntScatterMap
  • IntObjectScatterMap

4. Fastutil

Fastutil is a fast and compact framework that provides type-specific collections including primitive type maps.

4.1. Quick Example

Similar to Eclipse Collections and HPPC. Fastutil also provides primitive-to-primitive and primitive-to-Object typed association maps.

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

In questo articolo, abbiamo imparato come creare mappe primitive in Java usando Eclipse Collections, HPPC e Fastutil .

Come sempre, il codice di esempio per questo articolo è disponibile su GitHub.