forEach loop Java 8 para conjunto de entradas de mapas

82

Estoy tratando de convertir el antiguo convencional para cada bucle hasta java7 a java8 para cada bucle para un conjunto de entradas de mapa, pero obtengo un error. Aquí está el código que estoy tratando de convertir:

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

Estos son los cambios que hice:

map.forEach( Map.Entry<String, String> entry -> {
       System.out.println("Key : " + entry.getKey() + " Value : " + entry.getValue());

   }); 

Intenté hacer esto también:

Map.Entry<String, String> entry;
   map.forEach(entry -> {
       System.out.println("Key : " + entry.getKey() + " Value : " + entry.getValue());

   });

Pero aún enfrenta el error. El error que recibo para esto es: la firma de la expresión Lambda no coincide con la firma del método de interfaz funcionalaccept(String, String)

Siddharth Sachdeva
fuente

Respuestas:

191

Lea el javadoc : Map<K, V>.forEach()espera un BiConsumer<? super K,? super V>argumento as, y la firma del BiConsumer<T, U>método abstracto es accept(T t, U u).

Por lo tanto, debe pasarle una expresión lambda que tome dos entradas como argumento: la clave y el valor:

map.forEach((key, value) -> {
    System.out.println("Key : " + key + " Value : " + value);
});

Su código funcionaría si llama a forEach () en el conjunto de entrada del mapa, no en el mapa en sí:

map.entrySet().forEach(entry -> {
    System.out.println("Key : " + entry.getKey() + " Value : " + entry.getValue());
}); 
JB Nizet
fuente
Excelente. Ahora trabajando ambos. Pero, ¿cuál es mejor? ¿En qué caso el rendimiento sería mejor? @JBNizet
Siddharth Sachdeva
2
La segunda versión obliga Map.Entrya crear una instancia para cada entrada; el primero le da la clave y el valor sin instanciación. Por Map.Entrylo tanto, es un intermediario y puedes evitarlo usando la primera versión.
Marko Topolnik
5
@Marko Topolnik: para la mayoría de las Mapimplementaciones, las Map.Entryinstancias ya existen antes de la iteración y no es necesario crearlas . Aún así, no tener que lidiar con Map.Entryla acción es una ventaja en la legibilidad y tiene un pequeño potencial para un mejor rendimiento, ya que no se requieren invocaciones de métodos adicionales para recuperar la clave y el valor.
Holger
2
@Holger Haré hincapié en su implicación tácita: para la mayoría de lasMap implementaciones , pero no para todas , eso es cierto, ConcurrentHashMapsiendo un importante contraejemplo.
Marko Topolnik
1
@Marko Topolnik: pero cuando se itera sobre una totalidad ConcurrentHashMap, las instancias de entrada temporal son lo último de lo que preocuparse. Sin embargo, estamos de acuerdo en preferir de map.forEach((key, value) -> …);todos modos…
Holger
13

Quizás la mejor manera de responder preguntas como "¿qué versión es más rápida y cuál debo usar?" es mirar el código fuente:

map.forEach () - desde Map.java

default void forEach(BiConsumer<? super K, ? super V> action) {
    Objects.requireNonNull(action);
    for (Map.Entry<K, V> entry : entrySet()) {
        K k;
        V v;
        try {
            k = entry.getKey();
            v = entry.getValue();
        } catch(IllegalStateException ise) {
            // this usually means the entry is no longer in the map.
            throw new ConcurrentModificationException(ise);
        }
        action.accept(k, v);
    }
}

javadoc

map.entrySet (). forEach () - de Iterable.java

default void forEach(Consumer<? super T> action) {
    Objects.requireNonNull(action);
    for (T t : this) {
        action.accept(t);
    }
}

javadoc

Esto inmediatamente revela que map.forEach () también está usando Map.Entry internamente. Por lo tanto, no esperaría ningún beneficio de rendimiento al usar map.forEach () sobre map.entrySet (). ForEach () . Entonces, en su caso, la respuesta realmente depende de su gusto personal :)

Para obtener la lista completa de diferencias, consulte los enlaces javadoc proporcionados. ¡Feliz codificación!

Evgeny Tugarev
fuente
7

Puede utilizar el siguiente código para sus necesidades

map.forEach((k,v)->System.out.println("Item : " + k + " Count : " + v));
Shridhar Sangamkar
fuente
2
Esta respuesta es idéntica a parte de la respuesta proporcionada por JB Nizet 2 años antes y no proporciona información adicional útil.
Madbreaks
0
HashMap<String,Integer> hm = new HashMap();

 hm.put("A",1);
 hm.put("B",2);
 hm.put("C",3);
 hm.put("D",4);

 hm.forEach((key,value)->{
     System.out.println("Key: "+key + " value: "+value);
 });
vaibhav1111
fuente
Agregue alguna explicación a su respuesta. Esto ayudará a otros a adaptar su respuesta a sus propias necesidades. De la revisión .
Wai Ha Lee
0

API de transmisión

public void iterateStreamAPI(Map<String, Integer> map) {
    map.entrySet().stream().forEach(e -> System.out.println(e.getKey() + ":"e.getValue()));
}
vivek
fuente
0
String ss = "Pawan kavita kiyansh Patidar Patidar";
    StringBuilder ress = new StringBuilder();
    
    Map<Character, Integer> fre = ss.chars().boxed()
            .collect(Collectors.toMap(k->Character.valueOf((char) k.intValue()),k->1,Integer::sum));
    
      //fre.forEach((k, v) -> System.out.println((k + ":" + v)));
    
    fre.entrySet().forEach(e ->{
            //System.out.println(e.getKey() + ":" + e.getValue());
            //ress.append(String.valueOf(e.getKey())+e.getValue());
        }); 

    fre.forEach((k,v)->{
        //System.out.println("Item : " + k + " Count : " + v);
        ress.append(String.valueOf(k)+String.valueOf(v));
    });
    
    System.out.println(ress.toString());
Pawan Patidar
fuente
Si bien este fragmento de código puede ser la solución, incluir una explicación realmente ayuda a mejorar la calidad de su publicación. Recuerde que está respondiendo la pregunta para los lectores en el futuro, y es posible que esas personas no conozcan los motivos de su sugerencia de código.
Neo Anderson