¿Cómo puedo iterar de manera eficiente sobre cada entrada en un mapa de Java?

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

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

preguntado el 05 de septiembre de 08 a las 19:09

30 Respuestas

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

respondido 14 mar '19, 22:03

Si lo hace, no funcionará ya que Entry es una clase anidada en Map. java.sun.com/javase/6/docs/api/java/util/Map.html - ScArcher2

puede escribir la importación como "import java.util.Map.Entry;" y funcionará. - jjujuma

@Pureferret La única razón por la que podría querer usar un iterador es si necesita llamar a su remove mé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. - Assylias

Creo que el formulario Map.Entry es más claro que importar la clase interna en el espacio de nombres actual. - Josías Yoder

Tenga en cuenta que puede usar map.values() or map.keySet() si solo desea recorrer valores o claves. - Paraguay

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

  1. Usar iterador y Entrada del mapa

    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. Usar foreach y Entrada del mapa

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

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

    long i = 0;
    for (Integer key : map.keySet()) {
        i += key + map.get(key);
    }
    
  5. Usar juego de llaves y iterador

    long i = 0;
    Iterator<Integer> itr2 = map.keySet().iterator();
    while (itr2.hasNext()) {
        Integer key = itr2.next();
        i += key + map.get(key);
    }
    
  6. Usar en y Entrada del mapa

    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 Java 8 API de transmisión

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

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

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

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

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

  1. Para un mapa pequeño (100 elementos), la puntuación 0.308 es la 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, la puntuación 37.606 es la 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, la puntuación 1184.767 es la 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.

Respondido 05 ago 19, 21:08

@Viacheslav: muy buena respuesta. Solo me pregunto cómo se obstaculizan las apis de Java8, en su punto de referencia, al capturar lambdas ... (por ejemplo, long sum = 0; map.forEach( /* accumulate in variable sum*/); captura el sum de largo, que puede ser más lento que decir stream.mapToInt(/*whatever*/).sum por ejemplo. Por supuesto, no siempre se puede evitar capturar el estado, pero eso puede ser una adición razonable al banco. - GPI

Tu 8 prueba es incorrecta. accede a la misma variable desde diferentes subprocesos sin sincronización. Cambiar a AtomicInteger para resolver el problema. - talex

@ZhekaKozlov: mira los valores de error increíblemente grandes. Considere que un resultado de prueba de x±e implica que hubo resultado dentro del intervalo de x-e a x+e, por lo que el resultado más rápido (1184.767±332.968) rangos desde 852 a 1518, mientras que el segundo más lento (1706.676±436.867) corre entre 1270 y 2144, por lo que los resultados aún se superponen significativamente. Ahora mira el resultado más lento, 3289.866±1445.564, lo que implica divergir entre 1844 y 4735 y sabes qué que los resultados de estas pruebas no tienen sentido. - Holger

¿Qué hay de comparar las 3 implementaciones principales: HashMap, LinkedHashMap y TreeMap? - Thierry

# 1 y # 6 son exactamente iguales. Utilizando while contra un for loop 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 adecuadamente aisladas de factores externos no relacionados con las cosas que pretende probar. - ErikE

En Java 8 puede hacerlo de forma limpia y rápida utilizando las nuevas características de 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 k y v será inferido por el compilador y no es necesario utilizar Map.Entry más.

¡Pan comido!

Respondido el 07 de Septiembre de 16 a las 09:09

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 - Vitali Fedorenko

Esto no funcionará si desea hacer referencia a variables no finales declaradas fuera de su expresión lambda desde dentro de forEach () ... - Chris

@Chris Correcto. No funcionará si intentas usar efectivamente no final variables de fuera de la lambda. - El coordinador

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();
  // ...
}

Respondido 06 Feb 18, 22:02

Prefiero el bucle for que while .. for (Iterator entries = myMap.entrySet (). Iterator (); entries.hasNext ();) {...} Con esta sintaxis, el alcance de las 'entradas' se reduce al bucle for solamente . - Jai

@jpredham Tienes razón en que usar el for construir 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 la Iterator en alcance. (A menos que me falte algo ...) - comprando

IntelliJ me está dando errores en Entry thisEntry = (Entry) entries.next();: no reconoce Entry. ¿Es ese pseudocódigo para otra cosa? - JuanK

@JohnK intenta importar java.util.Map.Entry. - comprando

Esta solución no funcionará si tiene una clave de número entero y una clave de cadena. - usuario5778069

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();
    ...
}

HashMap es 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 en él). SortedMap devolverá entradas basadas en el orden natural de las claves, o un Comparator, si se proporciona. LinkedHashMap devolverá entradas en orden de inserción o en orden de acceso dependiendo de cómo se haya construido. EnumMap devuelve las entradas en el orden natural de las claves.

(Actualización: creo que esto ya no es cierto.) Nota, IdentityHashMap entrySet El iterador actualmente tiene una implementación peculiar que devuelve el mismo Map.Entry instancia para cada elemento en el entrySet! Sin embargo, cada vez que un nuevo iterador avanza el Map.Entry Está actualizado.

Respondido 09 Feb 18, 01:02

EnumMap también tiene este comportamiento peculiar junto con IdentityHashMap: Premraj

"LinkedHashMap devolverá entradas en [...] orden de acceso [...]" ... así que accedes a los elementos en el orden en que accedes a ellos? Ya sea tautológico o algo interesante que podría necesitar una digresión. ;-) - jpaugh

@jpaugh Solo accesos directos al LinkedHashMap contar. Aquellos a través iterator, spliterator, entrySet, etc., no modifique el pedido. - Tom Hawtin - táctica

1. aunqueif? 2. El último párrafo podría beneficiarse de un repaso. - Pedro Mortensen

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();
  // ...
}

Respondido 18 ago 09, 18:08

Deberías poner Iterator en un bucle for para limitar su alcance. - steve kuo

@SteveKuo ¿Qué quieres decir con "limitar su alcance"? - StudioWorks

@Estudio 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) entries al bucle for. - ComFreek

@ComFreek Oh, ya veo. No sabía que importaba tanto. - StudioWorks

Esta es una pregunta de dos partes:

Cómo iterar sobre las entradas de un mapa - @ ScArcher2 tiene contestado eso perfectamente.

¿Cuál es el orden de iteración? - si solo está usando Map, luego estrictamente hablando, hay sin garantías de pedido. Por lo tanto, no debería confiar en el orden dado por ninguna implementación. sin embargo, el SortedMap la interfaz se extiende Map y proporciona exactamente lo que está buscando: las implementaciones siempre proporcionarán un orden de clasificación coherente.

NavigableMap es otra extensión útil - esto es un SortedMap con métodos adicionales para buscar entradas por su posición ordenada en el conjunto de claves. Entonces, potencialmente, esto puede eliminar la necesidad de iterar en primer lugar; es posible que pueda encontrar el entry estás después de usar el higherEntry, lowerEntry, ceilingEntryo floorEntry métodos. La descendingMap método incluso te da un método explícito de invertir el orden transversal.

contestado el 23 de mayo de 17 a las 12:05

Hay varias formas de iterar sobre el mapa.

A continuación, se muestra una comparación de sus desempeños para un conjunto de datos comunes almacenados en el mapa almacenando un millón de pares de valores clave en el mapa y se iterará sobre el mapa.

1) Utilizando entrySet() en para cada bucle

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

Milisegundos 50

2) Utilizando keySet() en para cada bucle

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

Milisegundos 76

3) Utilizando 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();
}

Milisegundos 50

4) Utilizando keySet() e iterador

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

Milisegundos 75

Me he referido this link.

Respondido 18 Jul 15, 16:07

Los tiempos de ejecución se toman del artículo, que no utiliza Java Microbenchmarking Harness. Por tanto, los tiempos no son fiables, ya que el compilador JIT podría haber optimizado completamente el código, por ejemplo. - AlexB

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

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

Respondido 17 Oct 11, 01:10

Este no es el mejor enfoque, es mucho más eficiente usar entrySet (). Findbugs marcará este código (ver findbugs.sourceforge.net/…) - jeff olson

@JeffOlson meh, en realidad no. La búsqueda del mapa 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 benchmark, pero a veces también hago esto porque odio escribir los argumentos de tipo una y otra vez. Además, es muy probable que esto nunca sea su cuello de botella en el rendimiento, así que hágalo si hace que el código sea más legible. - kritzikratzi

más en detalle: 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 iguales. - kritzikratzi

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 verdad. - kritzikratzi

@Jeff Olson: el comentario de que la complejidad del “Big O” no cambia, cuando solo hay un factor constante, es correcto. Aún así, para mí es importante si una operación dura una hora o dos horas. Más importante, debe enfatizarse que el factor es no 2, como iterando sobre un entrySet() no soporta una búsqueda en absoluto; es solo un recorrido lineal de todas las entradas. Por el contrario, iterando sobre el keySet() y realizar una búsqueda por osos clave . búsqueda por clave, por lo que estamos hablando de cero búsquedas vs. n búsquedas aquí, n siendo el tamaño del Map. Entonces el factor está mucho más allá 2... - Holger

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

Respondido el 05 de Septiembre de 08 a las 23:09

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

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

contestado el 15 de mayo de 20 a las 10:05

Con Colecciones Eclipse, usarías el forEachKeyValue método en el MapIterable interfaz, que es heredada por el MutableMap y ImmutableMap interfaces 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 de Eclipse Collections.

Respondido 13 Abr '20, 20:04

En teoría, la forma más eficiente dependerá de qué 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 marcar alguna diferencia si usa map.keySet(), map.entrySet() o algo mas. Pero no puedo pensar en una razón por la que alguien lo escribiría así. Lo más probable es que lo que hagas no influya en el rendimiento.

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

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

contestado el 04 de mayo de 17 a las 23:05

Java 8

Tenemos forEach método que acepta un expresión lambda. También tenemos stream API. Considere un mapa:

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

Iterar sobre las claves:

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

Itera sobre valores:

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

Iterar las entradas (usando forEach 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 los flujos es que se pueden paralelizar fácilmente en caso de que lo deseemos. Simplemente necesitamos usar parallelStream() en lugar de stream() anterior.

forEachOrdered vs forEach con arroyos? La forEach no sigue el orden de encuentro (si se define) y es inherentemente no determinista en la naturaleza donde como el forEachOrdered lo hace. Entonces forEach no garantiza que se mantendrá el pedido. También revisa este para más.

Respondido 29 Abr '19, 06:04

lambda Expresión Java 8

En Java 1.8 (Java 8) esto se ha vuelto mucho más fácil usando para cada método de operaciones agregadas (Operaciones de transmisión) que se parece a los iteradores de Iterable Interfaz.

Simplemente copie y pegue la siguiente declaración en su código y cambie el nombre del mapa hash variable 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 Expresión Lambda. Esto es tan 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 Separador por lo mismo.

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

ACTUALIZACIÓN


Incluyendo enlaces de documentación a Oracle Docs. Para más sobre lambda ve a esto aquí y debe leer Operaciones agregadas y para Spliterator ve a esto aquí.

Respondido 30 Abr '19, 14:04

Java 8:

Puede usar expresiones lambda:

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

Para obtener más información, siga este.

Respondido 06 Feb 18, 03:02

@injecteer: Parece el motivo de las expresiones lambda - humilde novato

No necesita una transmisión si solo desea iterar sobre un mapa. myMap.forEach( (currentKey,currentValue) -> /* action */ ); es mucho más conciso. - Holger

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

  //...
}

Respondido el 07 de junio de 13 a las 15:06

En el mapa se puede iterar sobre keys y/o values y/o both (e.g., entrySet) depende de la persona interesada en_ Me gusta:

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

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

     for (Object value : map.values()) {
         //your Business logic...
     }
    
  3. Iterato a través del 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 los siguientes:

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

Respondido el 30 de Septiembre de 20 a las 16:09

Más compacto con Java 8:

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

Respondido 19 Abr '18, 13:04

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

respondido 16 mar '16, 16:03

El orden siempre dependerá de la implementación del mapa específico. Con Java 8, puede utilizar 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). El entrySet respaldado 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 Integer que son mayores de 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ás 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() + ", ");
        });
    }
}

Salida:

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,

Respondido el 30 de Septiembre de 20 a las 18:09

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

OR

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

Respondido el 07 de junio de 13 a las 15:06

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 de la reproducción en bucle de las claves es una prioridad para su aplicación, elija una Map implementación que mantiene las claves en el orden deseado.

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

Sí, absolutamente.

  • Cosas Map las implementaciones prometen un cierto orden de iteración, otras no.
  • Diferentes implementaciones de Map mantener un orden diferente de los pares clave-valor.

Vea esta tabla que creé que resume los diversos Map implementaciones empaquetadas con Java 11. Específicamente, observe el orden de iteración columna. Haga clic / toque para ampliar.

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

Puedes ver que hay Digital XNUMXk Map implementaciones manteniendo un orden:

  • TreeMap
  • ConcurrentSkipListMap
  • LinkedHashMap
  • EnumMap

NavigableMap interfaz.

Dos de ellos implementan el NavigableMap interfaz: TreeMap & ConcurrentSkipListMap.

El mas viejo SortedMap la interfaz es efectivamente suplantada por la nueva NavigableMap interfaz. Pero puede encontrar implementaciones de terceros que implementen solo la interfaz anterior.

Orden natural

Si quieres una Map que mantiene sus pares ordenados por el "orden natural" de la clave, utilice TreeMap or ConcurrentSkipListMap. El término "orden natural" significa la clase de los implementos de llaves Comparable. El valor devuelto por el compareTo El método se utiliza para la comparación en la clasificación.

Orden personalizado

Si desea especificar una rutina de clasificación personalizada para que sus claves se utilicen para mantener un orden ordenado, pase un Comparator implementación apropiada a la clase de sus claves. Utilizar cualquiera TreeMap or ConcurrentSkipListMap, pasando tu 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, utilice LinkedHashMap.

Orden de definición de enumeración

Si está utilizando una enumeración como DayOfWeek or Month como sus llaves, use el EnumMap clase. No solo esta clase altamente optimizado para usar muy poca memoria y ejecutarse muy rápido, mantiene sus pares en el orden definido por la enumeración. Para DayOfWeek, por ejemplo, la clave de DayOfWeek.MONDAY se encontrará por primera vez cuando se repita, y la clave de DayOfWeek.SUNDAY será el último.

Otras Consideraciones

Al elegir un Map implementación, también considere:

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

Ambas consideraciones se tratan en la tabla gráfica anterior.

Respondido 13 Abr '20, 06:04

Comentario tardío sobre una respuesta que también llegó tarde a la fiesta (pero muy informativa). +1 de mí por mencionar EnumMap, ya que es la primera vez que lo escucho. Probablemente haya muchos casos en los que esto pueda resultar útil. - user991710

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

Respondido el 14 de enero de 16 a las 20:01

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

respondido 16 mar '16, 15:03

Utilice Java 8:

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

Respondido 17 Abr '18, 20:04

Una solución iterativa eficaz sobre un mapa es una for bucle de Java 5 a 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 una mejora forEach

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

Respondido el 30 de Septiembre de 20 a las 13:09

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

            }

Respondido 13 Abr '16, 08:04

Sí, como muchas personas estuvieron de acuerdo, esta es la mejor manera de iterar sobre un Map.

Pero hay posibilidades de tirar nullpointerexception si el mapa es null. No te olvides de poner null .registrarse.

                                                 |
                                                 |
                                         - - - -
                                       |
                                       |
for (Map.Entry<String, Object> entry : map.entrySet()) {
    String key = entry.getKey();
    Object value = entry.getValue();
}

Respondido 06 Feb 18, 22:02

Hay muchas formas de hacer esto. A continuación se muestran algunos pasos sencillos:

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

respondido 22 mar '18, 10:03

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.