Come posso scorrere in modo efficiente ogni voce in una mappa Java?


3303

Se ho un oggetto che implementa l' Mapinterfaccia in Java e desidero iterare su ogni coppia contenuta al suo interno, qual è il modo più efficiente di passare attraverso la mappa?

L'ordinamento degli elementi dipenderà dall'implementazione della mappa specifica che ho per l'interfaccia?


38
In Java 8 usando Lambda Expression: stackoverflow.com/a/25616206/1503859
Nitin Mahesh,

Risposte:


5032
Map<String, String> map = ...
for (Map.Entry<String, String> entry : map.entrySet()) {
    System.out.println(entry.getKey() + "/" + entry.getValue());
}

93
In tal caso, non funzionerà poiché la voce è una classe nidificata nella mappa. java.sun.com/javase/6/docs/api/java/util/Map.html
ScArcher2

266
puoi scrivere l'importazione come "import java.util.Map.Entry;" e funzionerà.
jjujuma,

55
@Pureferret L'unico motivo per cui potresti voler utilizzare un iteratore è se devi chiamare il suo removemetodo. In tal caso, questa altra risposta ti mostra come farlo. Altrimenti, il ciclo avanzato come mostrato nella risposta sopra è la strada da percorrere.
Assylias,

102
Credo che il modulo Map.Entry sia più chiaro dell'importazione della classe interna nello spazio dei nomi corrente.
Josiah Yoder il

31
Si noti che è possibile utilizzare map.values()o map.keySet()se si desidera scorrere ciclicamente solo valori o chiavi.
dguay,

1216

Per riassumere le altre risposte e combinarle con ciò che so, ho trovato 10 modi principali per farlo (vedi sotto). Inoltre, ho scritto alcuni test delle prestazioni (vedi risultati di seguito). Ad esempio, se vogliamo trovare la somma di tutte le chiavi e i valori di una mappa, possiamo scrivere:

  1. Utilizzando iteratore e Map.Entry

    long i = 0;
    Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator();
    while (it.hasNext()) {
        Map.Entry<Integer, Integer> pair = it.next();
        i += pair.getKey() + pair.getValue();
    }
  2. Utilizzando foreach e Map.Entry

    long i = 0;
    for (Map.Entry<Integer, Integer> pair : map.entrySet()) {
        i += pair.getKey() + pair.getValue();
    }
  3. Utilizzo di forEach da Java 8

    final long[] i = {0};
    map.forEach((k, v) -> i[0] += k + v);
  4. Usando keySet e foreach

    long i = 0;
    for (Integer key : map.keySet()) {
        i += key + map.get(key);
    }
  5. Utilizzo di keySet e iteratore

    long i = 0;
    Iterator<Integer> itr2 = map.keySet().iterator();
    while (itr2.hasNext()) {
        Integer key = itr2.next();
        i += key + map.get(key);
    }
  6. Utilizzando per e Map.Entry

    long i = 0;
    for (Iterator<Map.Entry<Integer, Integer>> entries = map.entrySet().iterator(); entries.hasNext(); ) {
        Map.Entry<Integer, Integer> entry = entries.next();
        i += entry.getKey() + entry.getValue();
    }
  7. Utilizzo dell'API Java 8 Stream

    final long[] i = {0};
    map.entrySet().stream().forEach(e -> i[0] += e.getKey() + e.getValue());
  8. Utilizzo dell'API Java 8 Stream parallel

    final long[] i = {0};
    map.entrySet().stream().parallel().forEach(e -> i[0] += e.getKey() + e.getValue());
  9. Utilizzando IterableMap diApache Collections

    long i = 0;
    MapIterator<Integer, Integer> it = iterableMap.mapIterator();
    while (it.hasNext()) {
        i += it.next() + it.getValue();
    }
  10. Utilizzo delle raccolte MutableMap of Eclipse (CS)

    final long[] i = {0};
    mutableMap.forEachKeyValue((key, value) -> {
        i[0] += key + value;
    });

Test delle prestazioni (modalità = AverageTime, sistema = Windows 8.1 64 bit, Intel i7-4790 3,60 GHz, 16 GB)

  1. Per una piccola mappa (100 elementi), il punteggio 0,308 è il migliore

    Benchmark                          Mode  Cnt  Score    Error  Units
    test3_UsingForEachAndJava8         avgt  10   0.308 ±  0.021  µs/op
    test10_UsingEclipseMap             avgt  10   0.309 ±  0.009  µs/op
    test1_UsingWhileAndMapEntry        avgt  10   0.380 ±  0.014  µs/op
    test6_UsingForAndIterator          avgt  10   0.387 ±  0.016  µs/op
    test2_UsingForEachAndMapEntry      avgt  10   0.391 ±  0.023  µs/op
    test7_UsingJava8StreamApi          avgt  10   0.510 ±  0.014  µs/op
    test9_UsingApacheIterableMap       avgt  10   0.524 ±  0.008  µs/op
    test4_UsingKeySetAndForEach        avgt  10   0.816 ±  0.026  µs/op
    test5_UsingKeySetAndIterator       avgt  10   0.863 ±  0.025  µs/op
    test8_UsingJava8StreamApiParallel  avgt  10   5.552 ±  0.185  µs/op
  2. Per una mappa con 10000 elementi, il punteggio 37.606 è il migliore

    Benchmark                           Mode   Cnt  Score      Error   Units
    test10_UsingEclipseMap              avgt   10    37.606 ±   0.790  µs/op
    test3_UsingForEachAndJava8          avgt   10    50.368 ±   0.887  µs/op
    test6_UsingForAndIterator           avgt   10    50.332 ±   0.507  µs/op
    test2_UsingForEachAndMapEntry       avgt   10    51.406 ±   1.032  µs/op
    test1_UsingWhileAndMapEntry         avgt   10    52.538 ±   2.431  µs/op
    test7_UsingJava8StreamApi           avgt   10    54.464 ±   0.712  µs/op
    test4_UsingKeySetAndForEach         avgt   10    79.016 ±  25.345  µs/op
    test5_UsingKeySetAndIterator        avgt   10    91.105 ±  10.220  µs/op
    test8_UsingJava8StreamApiParallel   avgt   10   112.511 ±   0.365  µs/op
    test9_UsingApacheIterableMap        avgt   10   125.714 ±   1.935  µs/op
  3. Per una mappa con 100000 elementi, il punteggio 1184.767 è il migliore

    Benchmark                          Mode   Cnt  Score        Error    Units
    test1_UsingWhileAndMapEntry        avgt   10   1184.767 ±   332.968  µs/op
    test10_UsingEclipseMap             avgt   10   1191.735 ±   304.273  µs/op
    test2_UsingForEachAndMapEntry      avgt   10   1205.815 ±   366.043  µs/op
    test6_UsingForAndIterator          avgt   10   1206.873 ±   367.272  µs/op
    test8_UsingJava8StreamApiParallel  avgt   10   1485.895 ±   233.143  µs/op
    test5_UsingKeySetAndIterator       avgt   10   1540.281 ±   357.497  µs/op
    test4_UsingKeySetAndForEach        avgt   10   1593.342 ±   294.417  µs/op
    test3_UsingForEachAndJava8         avgt   10   1666.296 ±   126.443  µs/op
    test7_UsingJava8StreamApi          avgt   10   1706.676 ±   436.867  µs/op
    test9_UsingApacheIterableMap       avgt   10   3289.866 ±  1445.564  µs/op

Grafici (test delle prestazioni in base alle dimensioni della mappa)

Inserisci qui la descrizione dell'immagine

Tabella (test delle prestazioni in base alle dimensioni della mappa)

          100     600      1100     1600     2100
test10    0.333    1.631    2.752    5.937    8.024
test3     0.309    1.971    4.147    8.147   10.473
test6     0.372    2.190    4.470    8.322   10.531
test1     0.405    2.237    4.616    8.645   10.707
test2     0.376    2.267    4.809    8.403   10.910
test7     0.473    2.448    5.668    9.790   12.125
test9     0.565    2.830    5.952   13.220   16.965
test4     0.808    5.012    8.813   13.939   17.407
test5     0.810    5.104    8.533   14.064   17.422
test8     5.173   12.499   17.351   24.671   30.403

Tutti i test sono su GitHub .


9
@Viacheslav: bella risposta. Mi chiedo solo come le API Java8 siano ostacolate, nel tuo benchmark, catturando lambda ... (ad esempio long sum = 0; map.forEach( /* accumulate in variable sum*/);cattura il sumlungo, che può essere più lento di quanto si stream.mapToInt(/*whatever*/).sumpensi ad esempio. Naturalmente non puoi sempre evitare di catturare lo stato, ma potrebbe essere un'aggiunta ragionevole in panchina
GPI,

17
Il tuo 8 test è sbagliato. accede alla stessa variabile da thread diversi senza sincronizzazione. Passare a AtomicIntegerper risolvere il problema.
talex,

44
@ZhekaKozlov: guarda i valori di errore incredibilmente grandi. Considera che un risultato del test x±eimplica che ci sono risultati nell'intervallo da x-ea x+e, quindi il risultato più veloce ( 1184.767±332.968) varia da 852a 1518, mentre il secondo più lento ( 1706.676±436.867) scorre tra 1270e 2144, quindi i risultati si sovrappongono in modo significativo. Ora guarda il risultato più lento 3289.866±1445.564, che implica una divergenza tra 1844e 4735e sai che questi risultati del test sono privi di significato.
Holger

8
Che ne dici di confrontare le 3 implementazioni principali: HashMap, LinkedHashMap e TreeMap?
Thierry,

9
# 1 e # 6 sono esattamente gli stessi. L'uso di whilevs. un forciclo non è una tecnica diversa per iterare. E sono sorpreso che abbiano una tale variazione tra loro nei tuoi test, il che suggerisce che i test non sono adeguatamente isolati da fattori esterni non correlati alle cose che intendi testare.
ErikE,

294

In Java 8 puoi farlo in modo pulito e veloce usando le nuove funzionalità lambdas:

 Map<String,String> map = new HashMap<>();
 map.put("SomeKey", "SomeValue");
 map.forEach( (k,v) -> [do something with key and value] );

 // such as
 map.forEach( (k,v) -> System.out.println("Key: " + k + ": Value: " + v));

Il tipo di ke vverrà inferito dal compilatore e non è più necessario utilizzarlo Map.Entry.

Vai tranquillo!


12
A seconda di cosa vuoi fare con una mappa, puoi anche usare l'API di streaming sulle voci restituite da map.entrySet().stream() docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html
Vitalii Fedorenko il

1
Questo non funzionerà se si desidera fare riferimento a variabili non finali dichiarate all'esterno dell'espressione lambda dall'interno di forEach () ...
Chris

7
@Chris Correct. Non funzionerà se si tenta di utilizzare in modo efficace variabili non finali dall'esterno della lambda.
Il coordinatore,

243

Sì, l'ordine dipende dalla specifica implementazione della mappa.

@ ScArcher2 ha la sintassi Java 1.5 più elegante . In 1.4, farei una cosa del genere:

Iterator entries = myMap.entrySet().iterator();
while (entries.hasNext()) {
  Entry thisEntry = (Entry) entries.next();
  Object key = thisEntry.getKey();
  Object value = thisEntry.getValue();
  // ...
}

41
Preferire for-loop rispetto a while .. for (Iterator entry = myMap.entrySet (). Iterator (); entry.hasNext ();) {...} Con questa sintassi l'ambito 'entry' è ridotto al solo ciclo for .
jai,

8
@jpredham Hai ragione nel dire che usare il forcostrutto come for (Entry e : myMap.entrySet)non ti permetterà di modificare la raccolta, ma l'esempio come menzionato da @HanuAthena dovrebbe funzionare, dal momento che ti dà l' Iteratorambito. (A meno che non mi manchi qualcosa ...)
pkaeding dal

1
IntelliJ mi sta dando errori su Entry thisEntry = (Entry) entries.next();: non riconosce Entry. È pseudocodice per qualcos'altro?
JohnK,

1
@JohnK prova a importare java.util.Map.Entry.
pkaeding

1
Questa soluzione non funzionerà se si dispone di una chiave intera e una chiave String.

140

Il codice tipico per iterare su una mappa è:

Map<String,Thing> map = ...;
for (Map.Entry<String,Thing> entry : map.entrySet()) {
    String key = entry.getKey();
    Thing thing = entry.getValue();
    ...
}

HashMapè l'implementazione della mappa canonica e non fornisce garanzie (o anche se non dovrebbe cambiare l'ordine se non viene eseguita alcuna operazione di mutazione). SortedMaprestituirà le voci in base all'ordinamento naturale delle chiavi o Comparator, se fornito, a. LinkedHashMaprestituirà le voci nell'ordine di inserimento o nell'ordine di accesso a seconda di come è stata costruita. EnumMaprestituisce le voci in ordine naturale di chiavi.

(Aggiornamento: penso che questo non sia più vero. ) Nota, l' IdentityHashMap entrySetiteratore attualmente ha un'implementazione peculiare che restituisce la stessa Map.Entryistanza per ogni elemento nel entrySet! Tuttavia, ogni volta che un nuovo iteratore avanza, Map.Entryviene aggiornato.


6
EnumMap ha anche questo comportamento peculiare insieme a IdentityHashMap
Premraj

1
"LinkedHashMap restituirà le voci in [...] ordine di accesso [...]" ... in modo da accedere agli elementi nell'ordine in cui si accede ad essi? O tautologico, o qualcosa di interessante che potrebbe usare una digressione. ;-)
jpaugh il

5
@jpaugh Solo accessi diretti al LinkedHashMapconteggio. Quelli attraverso iterator, spliterator, entrySet, ecc, non modificare l'ordine.
Tom Hawtin: affronta il

1
1. peròse ? 2. L'ultimo paragrafo potrebbe trarre vantaggio da un ripasso.
Peter Mortensen,

122

Esempio di utilizzo di iteratore e generici:

Iterator<Map.Entry<String, String>> entries = myMap.entrySet().iterator();
while (entries.hasNext()) {
  Map.Entry<String, String> entry = entries.next();
  String key = entry.getKey();
  String value = entry.getValue();
  // ...
}

14
Dovresti inserire Iteratorun ciclo for per limitarne l'ambito.
Steve Kuo,

@SteveKuo Cosa intendi per "limitarne l'ambito"?
StudioWorks,

12
@StudioWorks for (Iterator<Map.Entry<K, V>> entries = myMap.entrySet().iterator(); entries.hasNext(); ) { Map.Entry<K, V> entry = entries.next(); }. Usando quel costrutto limitiamo l'ambito di (visibilità della variabile) entriesal ciclo for.
ComFreek,

3
@ComFreek Oh, capisco. Non sapevo che importasse così tanto.
StudioWorks

102

Questa è una domanda in due parti:

Come scorrere le voci di una mappa - @ ScArcher2 ha risposto perfettamente.

Qual è l'ordine di iterazione - se stai solo usando Map, quindi a rigor di termini, non ci sono garanzie per l'ordinazione . Quindi non dovresti davvero fare affidamento sull'ordinamento dato da qualsiasi implementazione. Tuttavia, l' SortedMapinterfaccia si estende Mape fornisce esattamente ciò che stai cercando: le implementazioni daranno sempre un ordinamento coerente.

NavigableMapè un'altra utile estensione : si tratta di un SortedMapmetodo aggiuntivo per trovare le voci in base alla posizione ordinata nel set di chiavi. Quindi potenzialmente questo può eliminare la necessità di iterazione, in primo luogo - si potrebbe essere in grado di trovare la specifica entrysiete dopo aver usato i higherEntry, lowerEntry, ceilingEntryo floorEntrymetodi. Il descendingMapmetodo fornisce anche un metodo esplicito per invertire l'ordine di attraversamento .


84

Esistono diversi modi per scorrere la mappa.

Ecco un confronto delle loro prestazioni per un set di dati comune archiviato nella mappa memorizzando un milione di coppie chiave-valore nella mappa e scorrerà sulla mappa.

1) Utilizzo di entrySet()in per ciascun loop

for (Map.Entry<String,Integer> entry : testMap.entrySet()) {
    entry.getKey();
    entry.getValue();
}

50 millisecondi

2) Usando keySet()in per ogni loop

for (String key : testMap.keySet()) {
    testMap.get(key);
}

76 millisecondi

3) Utilizzo entrySet()e iteratore

Iterator<Map.Entry<String,Integer>> itr1 = testMap.entrySet().iterator();
while(itr1.hasNext()) {
    Map.Entry<String,Integer> entry = itr1.next();
    entry.getKey();
    entry.getValue();
}

50 millisecondi

4) Utilizzo keySet()e iteratore

Iterator itr2 = testMap.keySet().iterator();
while(itr2.hasNext()) {
    String key = itr2.next();
    testMap.get(key);
}

75 millisecondi

Ho fatto riferimento this link.


1
I tempi di esecuzione sono tratti dall'articolo, che non utilizza il cablaggio Microbenchmarking Java. I tempi sono quindi inaffidabili, poiché il codice potrebbe, ad esempio, essere stato completamente ottimizzato dal compilatore JIT.
AlexB,

59

Il modo corretto per farlo è utilizzare la risposta accettata in quanto è la più efficiente. Trovo che il seguente codice appaia un po 'più pulito.

for (String key: map.keySet()) {
   System.out.println(key + "/" + map.get(key));
}

15
Questo non è l'approccio migliore, è molto più efficiente usare entrySet (). Findbugs contrassegnerà questo codice (vedi findbugs.sourceforge.net/… )
Jeff Olson,

6
@JeffOlson meh, non proprio. la ricerca della mappa è O (1), quindi entrambi i loop si comportano allo stesso modo. è vero, sarà leggermente più lento in un micro benchmark ma a volte lo faccio anche perché odio scrivere ripetutamente gli argomenti di tipo. Inoltre, questo probabilmente non sarà mai il collo di bottiglia delle prestazioni, quindi provalo se rende il codice più leggibile.
kritzikratzi,

4
più in dettaglio: O(1) = 2*O(1)è praticamente la definizione della grande notazione O. hai ragione, è un po 'più lento, ma in termini di complessità sono gli stessi.
kritzikratzi,

2
per collisione o no volevo dire che non importa se qualche collisione, ovviamente è una storia diversa se si hanno solo collisioni. quindi sei piuttosto meschino, ma sì, quello che stai dicendo è vero.
kritzikratzi,

2
@Jeff Olson: i commenti che la complessità della “Big O” non cambia, quando c'è solo un fattore costante, sono corretti. Tuttavia, per me importa se un'operazione richiede un'ora o due ore. Ancora più importante, si deve sottolineare che il fattore non lo è 2, poiché l'iterazione su un entrySet()non porta affatto una ricerca; è solo un attraversamento lineare di tutte le voci. Al contrario, iterando sopra keySet()ed eseguendo una ricerca per chiave porta una ricerca per chiave, quindi stiamo parlando di zero ricerche vs n ricerche qui, n essendo la dimensione della Map. Quindi il fattore va ben oltre 2...
Holger,

57

Cordiali saluti, puoi anche usare map.keySet()e map.values()se sei interessato solo a chiavi / valori della mappa e non all'altro.


42

Con Java 8 , puoi iterare Map usando forEach e lambda expression,

map.forEach((k, v) -> System.out.println((k + ":" + v)));

41

Con Eclipse Collezioni , è necessario utilizzare il forEachKeyValuemetodo sul MapIterableinterfaccia, che viene ereditato dai MutableMape ImmutableMapinterfacce e le loro implementazioni.

MutableBag<String> result = Bags.mutable.empty();
MutableMap<Integer, String> map = Maps.mutable.of(1, "One", 2, "Two", 3, "Three");
map.forEachKeyValue((key, value) -> result.add(key + value));
Assert.assertEquals(Bags.mutable.of("1One", "2Two", "3Three"), result);

Utilizzando una classe interna anonima, è possibile scrivere il codice come segue:

final MutableBag<String> result = Bags.mutable.empty();
MutableMap<Integer, String> map = Maps.mutable.of(1, "One", 2, "Two", 3, "Three");
map.forEachKeyValue(new Procedure2<Integer, String>()
{
    public void value(Integer key, String value)
    {
        result.add(key + value);
    }
});
Assert.assertEquals(Bags.mutable.of("1One", "2Two", "3Three"), result);

Nota: sono un committer per le raccolte Eclipse.


37

Lambda Expression Java 8

In Java 1.8 (Java 8) questo è diventato molto più semplice usando il metodo forEach da Operazioni aggregate ( operazioni Stream ) che sembra simile agli iteratori di Iterable Interface.

Basta copiare l'istruzione incolla di seguito nel codice e rinominare la variabile HashMap da hm alla variabile HashMap per stampare la coppia chiave-valore.

HashMap<Integer,Integer> hm = new HashMap<Integer, Integer>();
/*
 *     Logic to put the Key,Value pair in your HashMap hm
 */

// Print the key value pair in one line.

hm.forEach((k, v) -> System.out.println("key: " + k + " value:" + v));

// Just copy and paste above line to your code.

Di seguito è riportato il codice di esempio che ho provato a utilizzare Lambda Expression . Questa roba è così bella. Bisogna provare.

HashMap<Integer, Integer> hm = new HashMap<Integer, Integer>();
    Random rand = new Random(47);
    int i = 0;
    while(i < 5) {
        i++;
        int key = rand.nextInt(20);
        int value = rand.nextInt(50);
        System.out.println("Inserting key: " + key + " Value: " + value);
        Integer imap = hm.put(key, value);
        if( imap == null) {
            System.out.println("Inserted");
        } else {
            System.out.println("Replaced with " + imap);
        }               
    }

    hm.forEach((k, v) -> System.out.println("key: " + k + " value:" + v));

Output:

Inserting key: 18 Value: 5
Inserted
Inserting key: 13 Value: 11
Inserted
Inserting key: 1 Value: 29
Inserted
Inserting key: 8 Value: 0
Inserted
Inserting key: 2 Value: 7
Inserted
key: 1 value:29
key: 18 value:5
key: 2 value:7
key: 8 value:0
key: 13 value:11

Inoltre si può usare Spliterator per lo stesso.

Spliterator sit = hm.entrySet().spliterator();

AGGIORNARE


Compresi collegamenti alla documentazione di Oracle Docs. Per ulteriori informazioni su Lambda, vai a questo link e devi leggere Operazioni aggregate e per Spliterator vai a questo link .


36

In teoria, il modo più efficiente dipenderà dall'implementazione di Map. Il modo ufficiale per farlo è chiamare map.entrySet(), che restituisce un set di Map.Entry, ognuno dei quali contiene una chiave e un valore ( entry.getKey()eentry.getValue() ).

In un'implementazione idiosincratica, potrebbe fare qualche differenza se usi map.keySet(),map.entrySet() o qualcos'altro. Ma non riesco a pensare a un motivo per cui qualcuno lo scriverebbe così. Molto probabilmente non fa alcuna differenza nelle prestazioni ciò che fai.

E sì, l'ordine dipenderà dall'implementazione, nonché (eventualmente) dall'ordine di inserimento e da altri fattori difficili da controllare.

[modifica] Ho scritto in valueSet()origine, ma ovviamente in entrySet()realtà è la risposta.


36

Java 8

Abbiamo un forEachmetodo che accetta un'espressione lambda . Abbiamo anche API di streaming . Considera una mappa:

Map<String,String> sample = new HashMap<>();
sample.put("A","Apple");
sample.put("B", "Ball");

Scorrere le chiavi:

sample.keySet().forEach((k) -> System.out.println(k));

Scorrere i valori:

sample.values().forEach((v) -> System.out.println(v));

Scorrere le voci (utilizzando forEach e Streams):

sample.forEach((k,v) -> System.out.println(k + ":" + v)); 
sample.entrySet().stream().forEach((entry) -> {
            Object currentKey = entry.getKey();
            Object currentValue = entry.getValue();
            System.out.println(currentKey + ":" + currentValue);
        });

Il vantaggio con i flussi è che possono essere facilmente parallelizzati nel caso lo desiderassimo. Dobbiamo semplicemente usare parallelStream()al posto di stream()sopra.

forEachOrderedvs forEachcon flussi? L' forEachordine di incontro non segue (se definito) ed è intrinsecamente non deterministico in natura dove lo forEachOrderedfa. Quindi forEachnon garantisce che l'ordine verrà mantenuto. Controlla anche questo per ulteriori informazioni.


33

Java 8:

Puoi usare le espressioni lambda:

myMap.entrySet().stream().forEach((entry) -> {
    Object currentKey = entry.getKey();
    Object currentValue = entry.getValue();
});

Per ulteriori informazioni, segui questo .


@injecteer: sembra il motivo delle espressioni lambda
humblerookie

9
Non hai bisogno di uno stream se vuoi semplicemente scorrere su una mappa. myMap.forEach( (currentKey,currentValue) -> /* action */ );è molto più conciso.
Holger,

29

Prova questo con Java 1.4:

for( Iterator entries = myMap.entrySet().iterator(); entries.hasNext();){

  Entry entry = (Entry) entries.next();

  System.out.println(entry.getKey() + "/" + entry.getValue());

  //...
}

26

In Map si può passare da keyse / o valuese / o both (e.g., entrySet) a seconda del proprio interesse in_ Like:

  1. Scorrere la keys -> keySet()della mappa:

    Map<String, Object> map = ...;
    
    for (String key : map.keySet()) {
        //your Business logic...
    }
  2. Scorrere la values -> values()della mappa:

    for (Object value : map.values()) {
        //your Business logic...
    }
  3. Scorrere la both -> entrySet()della mappa:

    for (Map.Entry<String, Object> entry : map.entrySet()) {
        String key = entry.getKey();
        Object value = entry.getValue();
        //your Business logic...
    }

_Inoltre, ci sono 3 modi diversi per scorrere attraverso una mappa hash. Sono come sotto__

//1.
for (Map.Entry entry : hm.entrySet()) {
    System.out.print("key,val: ");
    System.out.println(entry.getKey() + "," + entry.getValue());
}

//2.
Iterator iter = hm.keySet().iterator();
while(iter.hasNext()) {
    Integer key = (Integer)iter.next();
    String val = (String)hm.get(key);
    System.out.println("key,val: " + key + "," + val);
}

//3.
Iterator it = hm.entrySet().iterator();
while (it.hasNext()) {
    Map.Entry entry = (Map.Entry) it.next();
    Integer key = (Integer)entry.getKey();
    String val = (String)entry.getValue();
    System.out.println("key,val: " + key + "," + val);
}

24

Più compatto con Java 8:

map.entrySet().forEach(System.out::println);

21

Se disponi di una mappa non tipizzata generica puoi utilizzare:

Map map = new HashMap();
for (Map.Entry entry : ((Set<Map.Entry>) map.entrySet())) {
    System.out.println(entry.getKey() + "/" + entry.getValue());
}

20
public class abcd{
    public static void main(String[] args)
    {
       Map<Integer, String> testMap = new HashMap<Integer, String>();
        testMap.put(10, "a");
        testMap.put(20, "b");
        testMap.put(30, "c");
        testMap.put(40, "d");
        for (Integer key:testMap.keySet()) {
            String value=testMap.get(key);
            System.out.println(value);
        }
    }
}

O

public class abcd {
    public static void main(String[] args)
    {
       Map<Integer, String> testMap = new HashMap<Integer, String>();
        testMap.put(10, "a");
        testMap.put(20, "b");
        testMap.put(30, "c");
        testMap.put(40, "d");
        for (Entry<Integer, String> entry : testMap.entrySet()) {
            Integer key=entry.getKey();
            String value=entry.getValue();
        }
    }
}

17

Se ho un oggetto che implementa l'interfaccia della mappa in Java e desidero iterare su ogni coppia contenuta al suo interno, qual è il modo più efficiente di passare attraverso la mappa?

Se l'efficienza del loop delle chiavi è una priorità per la tua app, scegli Mapun'implementazione che mantenga le chiavi nell'ordine desiderato.

L'ordinamento degli elementi dipenderà dall'implementazione della mappa specifica che ho per l'interfaccia?

Si assolutamente.

  • Alcuni Map implementazioni promettono un certo ordine di iterazione, altre no.
  • Diverse implementazioni per Mapmantenere un diverso ordinamento delle coppie chiave-valore.

Vedi questa tabella che ho creato riassumendo le varie Mapimplementazioni in bundle con Java 11. In particolare, nota la colonna dell'ordine di iterazione . Fai clic / tocca per ingrandire.

Tabella delle implementazioni delle mappe in Java 11, confrontando le loro caratteristiche

Puoi vedere che ci sono quattro Mapimplementazioni che mantengono un ordine :

  • TreeMap
  • ConcurrentSkipListMap
  • LinkedHashMap
  • EnumMap

NavigableMap interfaccia

Due di questi implementano l' NavigableMapinterfaccia: TreeMap& ConcurrentSkipListMap.

L' SortedMapinterfaccia precedente è effettivamente sostituita dall'interfaccia più recente NavigableMap. Ma potresti trovare implementazioni di terze parti che implementano solo l'interfaccia precedente.

Ordine naturale

Se si desidera un Mapelemento che mantiene le sue coppie disposte in base all '"ordine naturale" della chiave, utilizzare TreeMapo ConcurrentSkipListMap. Il termine "ordine naturale" indica la classe degli strumenti chiave Comparable. Il valore restituito dal compareTometodo viene utilizzato per il confronto nell'ordinamento.

Ordine personalizzato

Se si desidera specificare una routine di ordinamento personalizzata per le chiavi da utilizzare nel mantenimento di un ordine ordinato, passare Comparatorun'implementazione appropriata alla classe delle chiavi. Usa o TreeMapoppure ConcurrentSkipListMap, passando il tuo Comparator.

Ordine di inserimento originale

Se vuoi che le coppie della tua mappa siano mantenute nel loro ordine originale in cui le hai inserite nella mappa, usa LinkedHashMap.

Ordine di definizione dell'enum

Se stai usando un enum come DayOfWeeko Monthcome chiave, usa la EnumMapclasse. Questa classe non solo è altamente ottimizzata per usare pochissima memoria ed eseguire molto velocemente, ma mantiene le tue coppie nell'ordine definito dall'enum. Ad DayOfWeekesempio, la chiave di DayOfWeek.MONDAYverrà trovata per la prima volta quando viene ripetuta e la chiave diDayOfWeek.SUNDAY sarà l'ultima.

Altre considerazioni

Nella scelta di Mapun'implementazione, considera anche:

  • NULL. Alcune implementazioni vietano / accettano un NULL come chiave e / o valore.
  • Concorrenza. Se stai manipolando la mappa tra thread, devi utilizzare un'implementazione che supporti la concorrenza. O avvolgi la mappa con Collections::synchronizedMap(meno preferibile).

Entrambe queste considerazioni sono trattate nella tabella grafica sopra.


Commento in ritardo su una risposta che è anche in ritardo alla festa (ma molto istruttiva). +1 da parte mia per menzione EnumMap, poiché è la prima volta che ne sento parlare. Probabilmente ci sono molti casi in cui questo potrebbe tornare utile.
user991710

15

L'ordinamento dipenderà sempre dalla specifica implementazione della mappa. Utilizzando Java 8 è possibile utilizzare uno di questi:

map.forEach((k,v) -> { System.out.println(k + ":" + v); });

O:

map.entrySet().forEach((e) -> {
            System.out.println(e.getKey() + " : " + e.getValue());
        });

Il risultato sarà lo stesso (stesso ordine). La voce è supportata dalla mappa in modo da ottenere lo stesso ordine. Il secondo è utile in quanto consente di utilizzare lambdas, ad esempio se si desidera stampare solo oggetti Integer superiori a 5:

map.entrySet()
    .stream()
    .filter(e-> e.getValue() > 5)
    .forEach(System.out::println);

Il codice seguente mostra l'iterazione tramite LinkedHashMap e HashMap normale (esempio). Vedrai la differenza nell'ordine:

public class HMIteration {


    public static void main(String[] args) {
        Map<Object, Object> linkedHashMap = new LinkedHashMap<>();
        Map<Object, Object> hashMap = new HashMap<>();

        for (int i=10; i>=0; i--) {
            linkedHashMap.put(i, i);
            hashMap.put(i, i);
        }

        System.out.println("LinkedHashMap (1): ");
        linkedHashMap.forEach((k,v) -> { System.out.print(k + " (#="+k.hashCode() + "):" + v + ", "); });

        System.out.println("\nLinkedHashMap (2): ");

        linkedHashMap.entrySet().forEach((e) -> {
            System.out.print(e.getKey() + " : " + e.getValue() + ", ");
        });


        System.out.println("\n\nHashMap (1): ");
        hashMap.forEach((k,v) -> { System.out.print(k + " (#:"+k.hashCode() + "):" + v + ", "); });

        System.out.println("\nHashMap (2): ");

        hashMap.entrySet().forEach((e) -> {
            System.out.print(e.getKey() + " : " + e.getValue() + ", ");
        });
    }
}

LinkedHashMap (1):

10 (# = 10): 10, 9 (# = 9): 9, 8 (# = 8): 8, 7 (# = 7): 7, 6 (# = 6): 6, 5 (# = 5 ): 5, 4 (# = 4): 4, 3 (# = 3): 3, 2 (# = 2): 2, 1 (# = 1): 1, 0 (# = 0): 0,

LinkedHashMap (2):

10: 10, 9: 9, 8: 8, 7: 7, 6: 6, 5: 5, 4: 4, 3: 3, 2: 2, 1: 1, 0: 0,

HashMap (1):

0 (#: 0): 0, 1 (#: 1): 1, 2 (#: 2): 2, 3 (#: 3): 3, 4 (#: 4): 4, 5 (#: 5 ): 5, 6 (#: 6): 6, 7 (#: 7): 7, 8 (#: 8): 8, 9 (#: 9): 9, 10 (#: 10): 10,

HashMap (2):

0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, 10: 10,


14
    Iterator iterator = map.entrySet().iterator();
    while (iterator.hasNext()) {
        Map.Entry element = (Map.Entry)it.next();
        LOGGER.debug("Key: " + element.getKey());
        LOGGER.debug("value: " + element.getValue());    
    }

14

Usa Java 8:

map.entrySet().forEach(entry -> System.out.println(entry.getValue()));

13

Puoi farlo usando generici:

Map<Integer, Integer> map = new HashMap<Integer, Integer>();
Iterator<Map.Entry<Integer, Integer>> entries = map.entrySet().iterator();
while (entries.hasNext()) {
    Map.Entry<Integer, Integer> entry = entries.next();
    System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
}

12

Una soluzione iterativa efficace su una mappa è un ciclo 'per ogni' da Java 5 a Java 7. Ecco qui:

for (String key : phnMap.keySet()) {
    System.out.println("Key: " + key + " Value: " + phnMap.get(key));
}

Da Java 8 è possibile utilizzare un'espressione lambda per scorrere su una mappa. È un 'forEach' migliorato

phnMap.forEach((k,v) -> System.out.println("Key: " + k + " Value: " + v));

Se vuoi scrivere un condizionale per lambda puoi scriverlo in questo modo:

phnMap.forEach((k,v)->{
    System.out.println("Key: " + k + " Value: " + v);
    if("abc".equals(k)){
        System.out.println("Hello abc");
    }
});

10
           //Functional Oprations
            Map<String, String> mapString = new HashMap<>();
            mapString.entrySet().stream().map((entry) -> {
                String mapKey = entry.getKey();
                return entry;
            }).forEach((entry) -> {
                String mapValue = entry.getValue();
            });

            //Intrator
            Map<String, String> mapString = new HashMap<>();
            for (Iterator<Map.Entry<String, String>> it = mapString.entrySet().iterator(); it.hasNext();) {
                Map.Entry<String, String> entry = it.next();
                String mapKey = entry.getKey();
                String mapValue = entry.getValue();
            }

            //Simple for loop
            Map<String, String> mapString = new HashMap<>();
            for (Map.Entry<String, String> entry : mapString.entrySet()) {
                String mapKey = entry.getKey();
                String mapValue = entry.getValue();

            }

10

Ci sono molti modi per farlo. Di seguito sono riportati alcuni semplici passaggi:

Supponiamo di avere una mappa come:

Map<String, Integer> m = new HashMap<String, Integer>();

Quindi puoi fare qualcosa come il seguente per scorrere gli elementi della mappa.

// ********** Using an iterator ****************
Iterator<Entry<String, Integer>> me = m.entrySet().iterator();
while(me.hasNext()){
    Entry<String, Integer> pair = me.next();
    System.out.println(pair.getKey() + ":" + pair.getValue());
}

// *********** Using foreach ************************
for(Entry<String, Integer> me : m.entrySet()){
    System.out.println(me.getKey() + " : " + me.getValue());
}

// *********** Using keySet *****************************
for(String s : m.keySet()){
    System.out.println(s + " : " + m.get(s));
}

// *********** Using keySet and iterator *****************
Iterator<String> me = m.keySet().iterator();
while(me.hasNext()){
    String key = me.next();
    System.out.println(key + " : " + m.get(key));
}

9
package com.test;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class Test {

    public static void main(String[] args) {
        Map<String, String> map = new HashMap<String, String>();
        map.put("ram", "ayodhya");
        map.put("krishan", "mathura");
        map.put("shiv", "kailash");

        System.out.println("********* Keys *********");
        Set<String> keys = map.keySet();
        for (String key : keys) {
            System.out.println(key);
        }

        System.out.println("********* Values *********");
        Collection<String> values = map.values();
        for (String value : values) {
            System.out.println(value);
        }

        System.out.println("***** Keys and Values (Using for each loop) *****");
        for (Map.Entry<String, String> entry : map.entrySet()) {
            System.out.println("Key: " + entry.getKey() + "\t Value: "
                    + entry.getValue());
        }

        System.out.println("***** Keys and Values (Using while loop) *****");
        Iterator<Entry<String, String>> entries = map.entrySet().iterator();
        while (entries.hasNext()) {
            Map.Entry<String, String> entry = (Map.Entry<String, String>) entries
                    .next();
            System.out.println("Key: " + entry.getKey() + "\t Value: "
                    + entry.getValue());
        }

        System.out
                .println("** Keys and Values (Using java 8 using lambdas )***");
        map.forEach((k, v) -> System.out
                .println("Key: " + k + "\t value: " + v));
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.