¿Cómo itero eficientemente sobre cada entrada en un mapa de Java?

Respuestas:

5034
Map<String, String> map = ...
for (Map.Entry<String, String> entry : map.entrySet()) {
    System.out.println(entry.getKey() + "/" + entry.getValue());
}
ScArcher2
fuente
93
Si haces eso, entonces no funcionará ya que Entry es una Clase anidada en el Mapa. java.sun.com/javase/6/docs/api/java/util/Map.html
ScArcher2
266
puede escribir la importación como "import java.util.Map.Entry;" y funcionará
jjujuma
55
@Pureferret La única razón por la que puede querer usar un iterador es si necesita llamar a su removemétodo. Si ese es el caso, esta otra respuesta le muestra cómo hacerlo. De lo contrario, el bucle mejorado como se muestra en la respuesta anterior es el camino a seguir.
asilias
102
Creo que la forma Map.Entry es más clara que importar la clase interna en el espacio de nombres actual.
Josiah Yoder
31
Tenga en cuenta que puede usar map.values()o map.keySet()si desea recorrer solo valores o claves.
dguay
1217

Para resumir las otras respuestas y combinarlas con lo que sé, encontré 10 formas principales de hacerlo (ver más abajo). Además, escribí algunas pruebas de rendimiento (ver los resultados a continuación). Por ejemplo, si queremos encontrar la suma de todas las claves y valores de un mapa, podemos escribir:

  1. Usando iterador y 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. Usando foreach y Map.Entry

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

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

    long i = 0;
    for (Integer key : map.keySet()) {
        i += key + map.get(key);
    }
  5. El uso conjunto de claves y iterador

    long i = 0;
    Iterator<Integer> itr2 = map.keySet().iterator();
    while (itr2.hasNext()) {
        Integer key = itr2.next();
        i += key + map.get(key);
    }
  6. Usando para y 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. Usando la API Java 8 Stream

    final long[] i = {0};
    map.entrySet().stream().forEach(e -> i[0] += e.getKey() + e.getValue());
  8. Usando el Java 8 Stream API paralelo

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

    long i = 0;
    MapIterator<Integer, Integer> it = iterableMap.mapIterator();
    while (it.hasNext()) {
        i += it.next() + it.getValue();
    }
  10. Uso de colecciones MutableMap de Eclipse (CS)

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

Pruebas de rendimiento (modo = Tiempo promedio, sistema = Windows 8.1 de 64 bits, Intel i7-4790 3.60 GHz, 16 GB)

  1. Para un mapa pequeño (100 elementos), el puntaje 0.308 es el mejor

    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. Para un mapa con 10000 elementos, el puntaje 37.606 es el mejor

    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. Para un mapa con 100000 elementos, el puntaje 1184.767 es el mejor

    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

Gráficos (pruebas de rendimiento según el tamaño del mapa)

Ingrese la descripción de la imagen aquí

Tabla (pruebas de rendimiento según el tamaño del mapa)

          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

Todas las pruebas están en GitHub .

Viacheslav Vedenin
fuente
99
@Viacheslav: muy buena respuesta. Solo me pregunto cómo se obstaculizan las API de Java8, en su punto de referencia, al capturar lambdas ... (por ejemplo, long sum = 0; map.forEach( /* accumulate in variable sum*/);captura el sumlargo, que puede ser más lento de lo que se dice, stream.mapToInt(/*whatever*/).sumpor ejemplo. Por supuesto, no siempre puede evitar capturar el estado, pero eso puede ser una adición razonable a la banca.
GPI
17
Tu 8 prueba está mal. accede a la misma variable desde diferentes hilos sin sincronización. Cambiar a AtomicIntegerpara resolver el problema.
talex
44
@ZhekaKozlov: mira los valores de error increíblemente grandes. Considere que un resultado de prueba de x±eimplica que hubo un resultado dentro del intervalo de x-ea x+e, por lo que el resultado más rápido ( 1184.767±332.968) varía de 852a 1518, mientras que el segundo más lento ( 1706.676±436.867) se ejecuta entre 1270y 2144, por lo que los resultados aún se superponen significativamente. Ahora mire el resultado más lento, 3289.866±1445.564que implica divergentes entre 1844y 4735y usted sabe que estos resultados de la prueba no tienen sentido.
Holger
8
¿Qué hay de comparar las 3 implementaciones principales: HashMap, LinkedHashMap y TreeMap?
Thierry
99
# 1 y # 6 son exactamente lo mismo. Usar whilevs. un forbucle no es una técnica diferente para iterar. Y me sorprende que tengan tanta variación entre ellos en sus pruebas, lo que sugiere que las pruebas no están aisladas adecuadamente de factores externos no relacionados con las cosas que pretende probar.
ErikE
294

En Java 8 puede hacerlo limpio y rápido utilizando las nuevas características 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));

El tipo de ky vserá inferido por el compilador y ya no hay necesidad de usarlo Map.Entry.

¡Pan comido!

El coordinador
fuente
12
Dependiendo de lo que desee hacer con un mapa, también puede usar la API de transmisión en las entradas devueltas por map.entrySet().stream() docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html
Vitalii Fedorenko
1
Esto no funcionará si desea hacer referencia a variables no finales declaradas fuera de su expresión lambda desde forEach () ...
Chris
77
@ Chris Correcto. No funcionará si intenta utilizar efectivamente variables no finales desde fuera de la lambda.
El coordinador
243

Sí, el orden depende de la implementación específica del mapa.

@ ScArcher2 tiene la sintaxis Java 1.5 más elegante . En 1.4, haría algo como esto:

Iterator entries = myMap.entrySet().iterator();
while (entries.hasNext()) {
  Entry thisEntry = (Entry) entries.next();
  Object key = thisEntry.getKey();
  Object value = thisEntry.getValue();
  // ...
}
pkaeding
fuente
41
Prefiere for-loop que while ... for (Iterator entradas = myMap.entrySet (). Iterator (); Entradas.hasNext ();) {...} Con esta sintaxis, el alcance de 'entradas' se reduce al bucle for solamente .
jai
8
@jpredham Tiene razón en que usar la forconstrucción como for (Entry e : myMap.entrySet)no le permitirá modificar la colección, pero el ejemplo como @HanuAthena mencionó que debería funcionar, ya que le da el Iteratoralcance. (A menos que me falte algo ...)
pkaeding
1
IntelliJ me está dando errores en Entry thisEntry = (Entry) entries.next();: no reconoce Entry. ¿Es ese seudocódigo para otra cosa?
JohnK
1
@JohnK intente importar java.util.Map.Entry.
pkaeding
1
Esta solución no funcionará si tiene una clave entera y una clave de cadena.
140

El código típico para iterar sobre un mapa es:

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

HashMapes la implementación del mapa canónico y no ofrece garantías (o aunque no debería cambiar el orden si no se realiza ninguna operación de mutación). SortedMapdevolverá entradas según el orden natural de las claves, o a Comparator, si se proporciona. LinkedHashMapdevolverá entradas en orden de inserción u orden de acceso dependiendo de cómo se haya construido. EnumMapdevuelve entradas en el orden natural de las claves.

(Actualización: creo que esto ya no es cierto. ) Tenga en cuenta que el IdentityHashMap entrySetiterador actualmente tiene una implementación peculiar que devuelve la misma Map.Entryinstancia para cada elemento en el entrySet! Sin embargo, cada vez que un nuevo iterador avanza, Map.Entryse actualiza.

Tom Hawtin - tackline
fuente
66
EnumMap también tiene este comportamiento peculiar junto con IdentityHashMap
Premraj
1
"LinkedHashMap devolverá entradas en [...] orden de acceso [...]" ... ¿para que acceda a los elementos en el orden en que accede a ellos? Ya sea tautológico o algo interesante que podría usar una digresión. ;-)
jpaugh
55
@jpaugh Solo accesos directos al LinkedHashMapconteo. Aquellos a través de iterator, spliterator, entrySet, etc, no modifique la orden.
Tom Hawtin - tackline el
1
1. aunquesi ? 2. El último párrafo podría beneficiarse de un repaso.
Peter Mortensen
122

Ejemplo de uso de iterador y genéricos:

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();
  // ...
}
serg
fuente
14
Debe poner Iteratorun bucle for para limitar su alcance.
Steve Kuo
@SteveKuo ¿Qué quieres decir con "limitar su alcance"?
StudioWorks
12
@StudioWorks for (Iterator<Map.Entry<K, V>> entries = myMap.entrySet().iterator(); entries.hasNext(); ) { Map.Entry<K, V> entry = entries.next(); }. Al usar esa construcción, limitamos el alcance de (visibilidad de la variable) entriesal bucle for.
ComFreek
3
@ComFreek Oh, ya veo. No sabía que importaba tanto.
StudioWorks
102

Esta es una pregunta de dos partes:

Cómo iterar sobre las entradas de un Mapa : @ ScArcher2 lo ha respondido perfectamente.

¿Cuál es el orden de iteración ? Si solo está usando Map, estrictamente hablando, no hay garantías de pedido . Por lo tanto, no debe confiar realmente en el orden dado por ninguna implementación. Sin embargo, la SortedMapinterfaz se extiende Mapy proporciona exactamente lo que está buscando: las implementaciones siempre darán un orden de clasificación consistente.

NavigableMapes otra extensión útil : se trata de SortedMapmétodos adicionales para buscar entradas por su posición ordenada en el conjunto de claves. Por lo tanto, potencialmente esto puede eliminar la necesidad de la iteración en el primer lugar - que podría ser capaz de encontrar el específico entryque está después usando los higherEntry, lowerEntry, ceilingEntry, o floorEntrymétodos. El descendingMapmétodo incluso le brinda un método explícito para revertir el orden transversal .

serg10
fuente
84

Hay varias formas de iterar sobre el mapa.

Aquí hay una comparación de sus rendimientos para un conjunto de datos común almacenado en el mapa almacenando un millón de pares de valores clave en el mapa e iterará sobre el mapa.

1) Usando entrySet()en cada bucle

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

50 milisegundos

2) Usando keySet()en cada bucle

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

76 milisegundos

3) Uso entrySet()e iterador

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

50 milisegundos

4) Uso keySet()e iterador

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

75 milisegundos

Me he referido this link.

Darshan Patel
fuente
1
Los tiempos de ejecución se toman del artículo, que no utiliza el arnés de microbenchmarking de Java. Por lo tanto, los tiempos no son confiables, ya que el código podría, por ejemplo, haber sido completamente optimizado por el compilador JIT.
AlexB
59

La forma correcta de hacer esto es usar la respuesta aceptada, ya que es la más eficiente. Encuentro que el siguiente código se ve un poco más limpio.

for (String key: map.keySet()) {
   System.out.println(key + "/" + map.get(key));
}
Chris Dail
fuente
15
Este no es el mejor enfoque, es mucho más eficiente usar el entrySet (). Findbugs marcará este código (ver findbugs.sourceforge.net/… )
Jeff Olson el
66
@JeffOlson meh, en realidad no. la búsqueda de mapas es O (1), por lo que ambos bucles se comportan de la misma manera. Es cierto que será un poco más lento en un micro punto de referencia, pero a veces hago esto también porque odio escribir los argumentos tipo una y otra vez. Además, es muy probable que nunca sea su cuello de botella en el rendimiento, así que hágalo si hace que el código sea más legible.
kritzikratzi
44
más detalladamente: O(1) = 2*O(1)es más o menos la definición de la notación O grande. tienes razón en que funciona un poco más lento, pero en términos de complejidad son lo mismo.
kritzikratzi
2
por colisión o no, quise decir que no importa si tienes algunas colisiones, obviamente es una historia diferente si solo tienes colisiones. así que estás siendo bastante mezquino, pero sí, lo que estás diciendo es cierto.
kritzikratzi
2
@Jeff Olson: los comentarios de que la complejidad de "Big O" no cambia, cuando solo hay un factor constante, son correctos. Aún así, para mí es importante si una operación lleva una o dos horas. Más importante aún, debe enfatizarse que el factor no lo es 2, ya que iterar sobre un entrySet()no tiene ninguna búsqueda; Es solo un recorrido lineal de todas las entradas. En contraste, iterar sobre keySet()y realizar una búsqueda por tecla conlleva una búsqueda por tecla, por lo que estamos hablando de cero búsquedas frente a n búsquedas aquí, siendo n el tamaño de la Map. Así que el factor está mucho más allá 2...
Holger
57

Para su información, también puede usar map.keySet()y map.values()si solo le interesan las claves / valores del mapa y no el otro.

ckpwong
fuente
42

Con Java 8 , puede iterar Map usando forEach y la expresión lambda,

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

Con Eclipse Colecciones , utilizaría el forEachKeyValuemétodo en la MapIterableinterfaz, que se hereda por los MutableMapy las ImmutableMapinterfaces y sus implementaciones.

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

Usando una clase interna anónima, puede escribir el código de la siguiente manera:

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: Soy un committer para Eclipse Collections.

Donald Raab
fuente
37

Lambda Expression Java 8

En Java 1.8 (Java 8), esto se ha vuelto mucho más fácil mediante el uso de cada método de las operaciones de agregado ( operaciones de flujo ) que se parece a los iteradores de la interfaz Iterable .

Simplemente copie la declaración pegar debajo de su código y cambie el nombre de la variable HashMap de hm a su variable HashMap para imprimir el par clave-valor.

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.

A continuación se muestra el código de muestra que intenté usar Lambda Expression . Esto es genial. Deberías intentar.

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

También se puede usar Spliterator para lo mismo.

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

ACTUALIZAR


Incluyendo enlaces de documentación a Oracle Docs. Para obtener más información sobre Lambda, vaya a este enlace y debe leer Operaciones agregadas y para Spliterator, vaya a este enlace .

Nitin Mahesh
fuente
36

En teoría, la forma más eficiente dependerá de la implementación de Map. La forma oficial de hacer esto es llamar map.entrySet(), que devuelve un conjunto de Map.Entry, cada uno de los cuales contiene una clave y un valor ( entry.getKey()y entry.getValue()).

En una implementación idiosincrásica, podría tener alguna diferencia si se utiliza map.keySet(), map.entrySet()o alguna otra cosa. Pero no puedo pensar en una razón por la que alguien lo escribiría así. Lo más probable es que no influya en el rendimiento lo que haces.

Y sí, el orden dependerá de la implementación, así como (posiblemente) el orden de inserción y otros factores difíciles de controlar.

[editar] Escribí valueSet()originalmente pero, por supuesto, en entrySet()realidad es la respuesta.

Leigh Caldwell
fuente
36

Java 8

Tenemos un forEachmétodo que acepta una expresión lambda . También tenemos API de transmisión . Considere un mapa:

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

Iterar sobre las teclas:

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

Iterar sobre valores:

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

Iterar sobre entradas (Usar para cada uno y 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);
        });

La ventaja de las transmisiones es que pueden paralelizarse fácilmente en caso de que lo deseemos. Simplemente necesitamos usar parallelStream()en lugar de lo stream()anterior.

forEachOrderedvs forEachcon transmisiones? El forEachno sigue el orden de encuentro (si está definido) y es inherentemente no determinista en la naturaleza donde lo forEachOrderedhace. Por forEachlo tanto , no garantiza que se mantenga el pedido. También verifique esto para más.

akhil_mittal
fuente
33

Java 8:

Puedes usar expresiones lambda:

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

Para más información, sigue esto .

George Siggouroglou
fuente
@injecteer: Parece el motivo de las expresiones lambda
humblerookie
99
No necesita una secuencia si solo desea iterar sobre un mapa. myMap.forEach( (currentKey,currentValue) -> /* action */ );Es mucho más conciso.
Holger
29

Prueba esto con Java 1.4:

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

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

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

  //...
}
abods
fuente
26

En el mapa, se puede repetir keysy / o valuesy / o both (e.g., entrySet) depender de uno interesado en: Me gusta:

  1. Iterar a través keys -> keySet()del mapa:

    Map<String, Object> map = ...;
    
    for (String key : map.keySet()) {
        //your Business logic...
    }
  2. Iterar a través values -> values()del mapa:

    for (Object value : map.values()) {
        //your Business logic...
    }
  3. Iterar a través both -> entrySet()del mapa:

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

_ Además, hay 3 formas diferentes de iterar a través de un HashMap. Son como abajo__

//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);
}
Rupesh Yadav
fuente
24

Más compacto con Java 8:

map.entrySet().forEach(System.out::println);
bluehallu
fuente
21

Si tiene un mapa genérico sin tipo, puede usar:

Map map = new HashMap();
for (Map.Entry entry : ((Set<Map.Entry>) map.entrySet())) {
    System.out.println(entry.getKey() + "/" + entry.getValue());
}
dmunozfer
fuente
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();
        }
    }
}
Fathah Rehman P
fuente
17

Si tengo un objeto que implementa la interfaz Map en Java y deseo iterar sobre cada par que contiene, ¿cuál es la forma más eficiente de recorrer el mapa?

Si la eficiencia del bucle de las claves es una prioridad para su aplicación, elija una Mapimplementación que mantenga las claves en el orden deseado.

¿El orden de los elementos dependerá de la implementación específica del mapa que tenga para la interfaz?

Si, absolutamente.

  • Algunos Map implementaciones prometen un cierto orden de iteración, otras no.
  • Las diferentes implementaciones de Mapmantener un orden diferente de los pares clave-valor.

Vea esta tabla que creé resumiendo las diversas Mapimplementaciones incluidas con Java 11. Específicamente, observe la columna de orden de iteración . Haga clic / toque para ampliar.

Tabla de implementaciones de mapas en Java 11, comparando sus características

Puede ver que hay cuatro Mapimplementaciones que mantienen un orden :

  • TreeMap
  • ConcurrentSkipListMap
  • LinkedHashMap
  • EnumMap

NavigableMap interfaz

Dos de ellos implementan la NavigableMapinterfaz: TreeMap& ConcurrentSkipListMap.

La SortedMapinterfaz más antigua es suplantada efectivamente por la NavigableMapinterfaz más nueva . Pero puede encontrar implementaciones de terceros que implementan solo la interfaz anterior.

Orden natural

Si desea un Mapque mantenga sus pares ordenados por el "orden natural" de la clave, use TreeMapo ConcurrentSkipListMap. El término "orden natural" significa la clase de los implementos de claves Comparable. El valor devuelto por elcompareTo método se utiliza para comparar en la clasificación.

Orden personalizado

Si desea especificar una rutina de clasificación personalizada para que sus claves se usen para mantener un orden ordenado, pase una Comparatorimplementación adecuada a la clase de sus claves. Use cualquiera TreeMapo ConcurrentSkipListMap, pasando su Comparator.

Orden de inserción original

Si desea que los pares de su mapa se mantengan en su orden original en el que los insertó en el mapa, use LinkedHashMap.

Orden de definición de enumeración

Si está utilizando una enumeración como DayOfWeeko Monthcomo sus claves, use la EnumMapclase Esta clase no solo está altamente optimizada para usar muy poca memoria y ejecutarse muy rápido, sino que mantiene sus pares en el orden definido por la enumeración. Por DayOfWeekejemplo, la clave de DayOfWeek.MONDAYse encontrará primero cuando se itera, y la clave de DayOfWeek.SUNDAYserá la última.

Otras Consideraciones

Al elegir una Mapimplementación, también considere:

  • NULOS Algunas implementaciones prohíben / aceptan un NULL como clave y / o valor.
  • Concurrencia. Si está manipulando el mapa a través de subprocesos, debe usar una implementación que admita concurrencia. O envuelva el mapa con Collections::synchronizedMap(menos preferible).

Ambas consideraciones están cubiertas en la tabla gráfica anterior.

Albahaca Bourque
fuente
Comentario tardío sobre una respuesta que también llega tarde a la fiesta (pero muy informativa). +1 de mi parte por mencionarlo EnumMap, ya que es la primera vez que escucho de él. Probablemente hay muchos casos en los que esto podría ser útil.
user991710
15

El orden siempre dependerá de la implementación específica del mapa. Usando Java 8 puede usar cualquiera de estos:

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

O:

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

El resultado será el mismo (mismo orden). La entrada está respaldada por el mapa para que obtenga el mismo orden. El segundo es útil ya que le permite usar lambdas, por ejemplo, si solo desea imprimir solo objetos enteros que sean mayores que 5:

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

El siguiente código muestra la iteración a través de LinkedHashMap y HashMap normal (ejemplo). Verá la diferencia en el orden:

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,

Witold Kaczurba
fuente
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());    
    }
Fadid
fuente
14

Utiliza Java 8:

map.entrySet().forEach(entry -> System.out.println(entry.getValue()));
ABHAY JOHRI
fuente
13

Puedes hacerlo usando genéricos:

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());
}
Pranoti
fuente
12

Una solución iterativa efectiva sobre un mapa es un 'para cada' bucle desde Java 5 hasta Java 7. Aquí está:

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

Desde Java 8 puede usar una expresión lambda para iterar sobre un Mapa. Es un 'forEach' mejorado

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

Si desea escribir un condicional para lambda, puede escribirlo así:

phnMap.forEach((k,v)->{
    System.out.println("Key: " + k + " Value: " + v);
    if("abc".equals(k)){
        System.out.println("Hello abc");
    }
});
anandchaugule
fuente
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();

            }
Sajad NasiriNezhad
fuente
10

Hay muchas formas de hacer esto. A continuación hay algunos pasos simples:

Supongamos que tiene un mapa como:

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

Luego puede hacer algo como lo siguiente para iterar sobre los elementos del mapa.

// ********** 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));
}
Utpal Kumar
fuente
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));
    }
}
Rupendra Sharma
fuente