forEach loop Java 8 for Map entry set

82

Próbuję przekonwertować stare konwencjonalne dla każdej pętli do java7 na java8 dla każdej pętli dla zestawu pozycji mapy, ale otrzymuję błąd. Oto kod, który próbuję przekonwertować:

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

Oto zmiany, które wprowadziłem:

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

   }); 

Próbowałem też to zrobić:

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

   });

Ale wciąż napotykam błąd. Pojawia się błąd: Podpis wyrażenia lambda nie jest zgodny z sygnaturą metody interfejsu funkcjonalnegoaccept(String, String)

Siddharth Sachdeva
źródło

Odpowiedzi:

193

Przeczytaj javadoc : Map<K, V>.forEach()oczekuje BiConsumer<? super K,? super V>argumentu a as, a podpis BiConsumer<T, U>metody abstrakcyjnej to accept(T t, U u).

Więc powinieneś przekazać mu wyrażenie lambda, które przyjmuje dwa dane wejściowe jako argument: klucz i wartość:

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

Twój kod zadziałałby, gdybyś wywołał forEach () na zbiorze wejściowym mapy, a nie na samej mapie:

map.entrySet().forEach(entry -> {
    System.out.println("Key : " + entry.getKey() + " Value : " + entry.getValue());
}); 
JB Nizet
źródło
Świetny. Teraz pracuję zarówno. Ale który z nich jest lepszy? W którym przypadku wydajność byłaby lepsza? @JBNizet
Siddharth Sachdeva
2
Druga wersja wymusza utworzenie Map.Entryinstancji dla każdego wpisu; pierwszy podaje klucz i wartość bez tworzenia instancji. Dlatego Map.Entryjest pośrednikiem i można tego uniknąć używając pierwszej wersji.
Marko Topolnik
5
@Marko Topolnik: w przypadku większości Mapimplementacji Map.Entryinstancje istnieją już przed iteracją i nie trzeba ich tworzyć. Jednak brak konieczności zajmowania się Map.Entryw akcji jest korzystny dla czytelności i ma niewielki potencjał dla lepszej wydajności, ponieważ do pobrania klucza i wartości nie są wymagane żadne dodatkowe wywołania metod.
Holger
2
@Holger Podkreślę twoją cichą implikację: dla większości, ale nie wszystkich , Mapimplementacji jest to prawdą, ConcurrentHashMapbędąc ważnym kontrprzykładem.
Marko Topolnik
1
@Marko Topolnik: ale podczas iteracji przez cały ConcurrentHashMapczas, tymczasowe instancje wejścia są ostatnią rzeczą, o którą należy się martwić. Niemniej jednak zgadzamy się na preferowanie map.forEach((key, value) -> …);mimo wszystko…
Holger
13

Może najlepszy sposób, aby odpowiedzieć na pytania typu „która wersja jest szybsza, a której użyć?” to zajrzeć do kodu źródłowego:

map.forEach () - z 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 () - z Iterable.java

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

javadoc

To natychmiast ujawnia, że map.forEach () również używa wewnętrznie Map.Entry . Więc nie spodziewałbym się żadnych korzyści w zakresie wydajności przy używaniu map.forEach () nad map.entrySet (). ForEach () . Więc w twoim przypadku odpowiedź naprawdę zależy od twojego osobistego gustu :)

Aby uzyskać pełną listę różnic, zapoznaj się z podanymi linkami javadoc. Miłego kodowania!

Evgeny Tugarev
źródło
7

Możesz użyć następującego kodu dla swojego wymagania

map.forEach((k,v)->System.out.println("Item : " + k + " Count : " + v));
Shridhar Sangamkar
źródło
2
Ta odpowiedź jest identyczna z częścią odpowiedzi udzielonej przez JB Nizet 2 lata wcześniej i nie dostarcza żadnych dodatkowych, przydatnych informacji.
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
źródło
Dodaj wyjaśnienie do swojej odpowiedzi. Pomoże to innym dostosować Twoją odpowiedź do ich własnych potrzeb. Z recenzji .
Wai Ha Lee
0

Stream API

public void iterateStreamAPI(Map<String, Integer> map) {
    map.entrySet().stream().forEach(e -> System.out.println(e.getKey() + ":"e.getValue()));
}
vivek
źródło
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
źródło
Chociaż ten fragment kodu może być rozwiązaniem, dołączenie wyjaśnienia naprawdę pomaga poprawić jakość Twojego posta. Pamiętaj, że odpowiadasz na pytanie do czytelników w przyszłości, a osoby te mogą nie znać powodów, dla których zaproponowałeś kod.
Neo Anderson