цикл forEach Java 8 для набора записей Map

82

Я пытаюсь преобразовать старый стандарт для каждого цикла до java7 в java8 для каждого цикла для набора записей карты, но я получаю сообщение об ошибке. Вот код, который я пытаюсь преобразовать:

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

Вот изменения, которые я сделал:

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

   }); 

Я тоже пробовал это делать:

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

   });

Но все еще сталкивается с ошибкой. Ошибка, которую я получаю, следующая: подпись лямбда-выражения не соответствует подписи метода функционального интерфейса.accept(String, String)

Сиддхартх Сачдева
источник

Ответы:

193

Прочтите javadoc : Map<K, V>.forEach()ожидает BiConsumer<? super K,? super V>аргумент as, а подпись BiConsumer<T, U>абстрактного метода - accept(T t, U u).

Таким образом, вы должны передать ему лямбда-выражение, которое принимает в качестве аргумента два входа: ключ и значение:

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

Ваш код будет работать, если вы вызовете forEach () для набора записей карты, а не для самой карты:

map.entrySet().forEach(entry -> {
    System.out.println("Key : " + entry.getKey() + " Value : " + entry.getValue());
}); 
JB Nizet
источник
Отлично. Сейчас работают оба. Но какой способ лучше? В каком случае производительность будет лучше? @JBNizet
Сиддхарт Сачдева
2
Вторая версия заставляет Map.Entryсоздавать экземпляр для каждой записи; первый дает вам ключ и значение без создания экземпляра. Следовательно Map.Entry, это посредник, и вы можете избежать этого, используя первую версию.
Марко Топольник
5
@Marko Topolnik: для большинства Mapреализаций Map.Entryэкземпляры уже существуют до итерации, и их не нужно создавать. Тем не менее, отсутствие необходимости иметь дело с Map.Entryдействием является преимуществом для удобочитаемости и имеет небольшой потенциал для повышения производительности, поскольку для получения ключа и значения не требуется дополнительных вызовов методов.
Хольгер
2
@Holger Я подчеркиваю ваше молчаливое значение: для большинства, но не для всех , Mapреализаций, которые верны, ConcurrentHashMapявляются важным контрпримером.
Марко Топольник
1
@Marko Topolnik: но при итерации всего ConcurrentHashMapвременные экземпляры записей - это последнее, о чем следует беспокоиться. Тем не менее, мы согласны в map.forEach((key, value) -> …);любом случае отдать предпочтение …
Хольгер
13

Может быть, лучший способ ответить на вопросы типа «какая версия быстрее и какую мне использовать?» посмотреть на исходный код:

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

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

javadoc

Это сразу показывает, что map.forEach () также использует Map.Entry для внутренних целей . Поэтому я бы не ожидал какого-либо повышения производительности при использовании map.forEach () по сравнению с map.entrySet (). ForEach () . Так что в вашем случае ответ действительно зависит от вашего личного вкуса :)

Полный список различий см. По предоставленным ссылкам на javadoc. Удачного кодирования!

Евгений Тугарев
источник
7

Вы можете использовать следующий код для вашего требования

map.forEach((k,v)->System.out.println("Item : " + k + " Count : " + v));
Шридхар Сангамкар
источник
2
Этот ответ идентичен части ответа, предоставленного Дж. Б. Низетом двумя годами ранее, и не содержит дополнительной полезной информации.
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
источник
Пожалуйста, добавьте пояснение к своему ответу. Это поможет другим адаптировать ваш ответ к своим потребностям. Из обзора .
Вай Ха Ли
0

Stream API

public void iterateStreamAPI(Map<String, Integer> map) {
    map.entrySet().stream().forEach(e -> System.out.println(e.getKey() + ":"e.getValue()));
}
вивек
источник
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());
Паван Патидар
источник
Хотя этот фрагмент кода может быть решением, включение объяснения действительно помогает улучшить качество вашего сообщения. Помните, что вы отвечаете на вопрос читателей в будущем, и эти люди могут не знать причин вашего предложения кода.
Нео Андерсон,