Как мне эффективно перебирать каждую запись в Java Map?

avatar
iMack
5 сентября 2008 в 21:12
2768155
47
3600

Если у меня есть объект, реализующий интерфейс Map на Java, и я хочу перебрать каждую содержащуюся в нем пару, какой способ просмотра карты является наиболее эффективным?

Будет ли порядок элементов зависеть от конкретной реализации карты, которая у меня есть для интерфейса?

Источник
Nitin Mahesh
25 июля 2015 в 18:31
41

В Java 8 с использованием лямбда-выражения: coderhelper.com/a/25616206/1503859

akhil_mittal
10 октября 2018 в 12:45
5

Java 8: coderhelper.com/questions/46898/…

Ответы (47)

avatar
ScArcher2
5 сентября 2008 в 21:15
5439
Map<String, String> map = ...
for (Map.Entry<String, String> entry : map.entrySet()) {
    System.out.println(entry.getKey() + "/" + entry.getValue());
}

В Java 10+:

for (var entry : map.entrySet()) {
    System.out.println(entry.getKey() + "/" + entry.getValue());
}
ScArcher2
22 марта 2010 в 13:30
94

Если вы это сделаете, это не сработает, поскольку Entry является вложенным классом в Map. java.sun.com/javase/6/docs/api/java/util/Map.html

jjujuma
30 апреля 2010 в 10:34
277

вы можете записать импорт как «import java.util.Map.Entry;» и это будет работать.

assylias
8 октября 2012 в 10:34
56

@Pureferret Единственная причина, по которой вы можете захотеть использовать итератор, - это вызов его метода remove. Если это так, этот другой ответ покажет вам, как это сделать. В противном случае лучше использовать расширенный цикл, показанный в ответе выше.

Josiah Yoder
4 декабря 2014 в 20:31
107

Я считаю, что форма Map.Entry более понятна, чем импорт внутреннего класса в текущее пространство имен.

dguay
12 октября 2016 в 21:03
34

Обратите внимание, что вы можете использовать map.values() или map.keySet(), если хотите перебирать только значения или ключи.

avatar
anand krish
29 сентября 2021 в 15:35
4

Это все возможные способы итерации HashMap.

HashMap<Integer,String> map=new HashMap<Integer,String>();
    map.put(1,"David");  //Adding elements in Map
    map.put(2,"John");
    map.put(4,"Samyuktha");
    map.put(3,"jasmin");
    System.out.println("Iterating Hashmap...");

    //way 1 (java 8 Method)
    map.forEach((key, value) -> {
        System.out.println(key+" : "+ value);
    });

    //way 2 (java 7 Method)
    for(Map.Entry me : map.entrySet()){
        System.out.println(me.getKey()+" "+me.getValue());
    }

    //way 3 (Legacy type to iterate HashMap)
    Iterator iterator = map.entrySet().iterator();//map.keySet().iterator()
    while (iterator.hasNext())
    {
        Map.Entry me =(Map.Entry)iterator.next();
        System.out.println(me.getKey()+" : "+ me.getValue());
    }
    
}
avatar
Rajesh Kumar Duraisamy
10 июня 2021 в 07:36
7

Ниже приведены способы итерации HashMaps

Метод Java 8:

hashMap.forEach((key, value) -> {
    System.out.println("Value of " + key + " is " + value);
});

Метод Java 7:

for (Map.Entry entry : hashMap.entrySet()) {
    System.out.println(entry.getKey() + " Value is " + entry.getValue());
}

Пожалуйста, обратитесь к ссылкам ниже для получения дополнительной информации о hashmap

https://beginnersbug.com/get-key-and-value-from-hashmap-in-java/

https://docs.oracle.com/javase/8/docs/api/java/util/Map.html

avatar
Badri Paudel
11 января 2021 в 16:04
3

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

Демонстрационная карта:

 Map<String, String> map = new HashMap();
  map.put("name", "Name");
  map.put("age", "23");
  map.put("address", "NP");
  map.put("faculty", "BE");
  map.put("major", "CS");
  map.put("head", "MDK");
 

Чтобы получить только ключ, вы можете использовать map.keySet(); следующим образом:

for(String key : map.keySet()) {
      System.out.println(key);
  }

Чтобы получить только значение, вы можете использовать map.values(); следующим образом:

      for(String value : map.values()) {
      System.out.println(value);
  }

Чтобы получить и ключ, и его значение, вы все равно можете использовать map.keySet(); и получить соответствующее значение, например:

 //this prints the key value pair
  for (String k : map.keySet()) {
        System.out.println(k + " " + map.get(k) + " ");
    }

map.get(key) дает значение, указанное этим ключом.

avatar
Dubstep
15 сентября 2020 в 22:53
3
Map<String, String> map = 
for (Map.Entry<String, String> entry : map.entrySet()) {
    MapKey = entry.getKey() 
    MapValue = entry.getValue();
}
avatar
Younes El Ouarti
14 июня 2020 в 21:19
7

Начиная с Java 10, вы можете использовать вывод локальной переменной (также известный как «var»), чтобы сделать многие уже доступные ответы менее раздутыми. Например:

for (var entry : map.entrySet()) {
    System.out.println(entry.getKey() + " : " + entry.getValue());
}
avatar
Ali Akram
6 января 2020 в 07:44
8

Map.forEach

А как насчет простого использования Map::forEach, где ключ и значение передаются на ваш BiConsumer?

map.forEach((k,v)->{
    System.out.println(k+"->"+v);
});
Basil Bourque
6 января 2020 в 07:51
0

Об этом рассказала в ответе Лова Читтумури. Также рассматривается как пункт 3 в ответе Вячеслава Веденина, получившего большое количество голосов.

Mahbubur Rahman Khan
5 марта 2020 в 22:02
0

Но доступно только на этикетке API 24

avatar
Basil Bourque
26 октября 2019 в 19:44
22

Если у меня есть объект, реализующий интерфейс карты в Java, и я хочу перебрать каждую содержащуюся в нем пару, каков наиболее эффективный способ просмотра карты?

Если эффективность зацикливания ключей является приоритетом для вашего приложения, выберите реализацию Map, которая поддерживает ключи в желаемом порядке.

Будет ли порядок элементов зависеть от конкретной реализации карты, которая у меня есть для интерфейса?

Да, конечно.

  • Некоторые реализации Map обещают определенный порядок итераций, другие нет.
  • Различные реализации Map поддерживают разный порядок пар "ключ-значение".

См. Эту таблицу, которую я создал, обобщая различные реализации Map в комплекте с Java 11. В частности, обратите внимание на столбец порядок итераций . Щелкните / коснитесь для увеличения.

Table of map implementations in Java 11, comparing their features

Как видите, существует четыре реализации Map, поддерживающих порядок :

  • TreeMap
  • ConcurrentSkipListMap
  • LinkedHashMap
  • EnumMap

NavigableMap интерфейс

Два из них реализуют интерфейс NavigableMap: TreeMap & ConcurrentSkipListMap.

Старый интерфейс SortedMap заменен новым интерфейсом NavigableMap. Но вы можете найти сторонние реализации, реализующие только старый интерфейс.

Естественный порядок

Если вам нужен Map, который хранит свои пары в «естественном порядке» ключа, используйте TreeMap или <3737737283372> >. Термин «естественный порядок» означает класс реализаций ключей Comparable. Значение, возвращаемое методом compareTo, используется для сравнения при сортировке.

Под заказ

Если вы хотите указать настраиваемую процедуру сортировки для ключей, которая будет использоваться для поддержания порядка сортировки, передайте реализацию Comparator, соответствующую классу ваших ключей. Используйте TreeMap или ConcurrentSkipListMap, передав ваш Comparator.

Исходный заказ на размещение

Если вы хотите, чтобы пары вашей карты сохранялись в том порядке, в котором вы их вставляли на карту, используйте LinkedHashMap.

Порядок определения перечисления

Если вы используете перечисление, такое как DayOfWeek или Month в качестве ключей, используйте класс <2863711>. Этот класс не только очень оптимизирован для использования очень небольшого объема памяти и работает очень быстро, он поддерживает ваши пары в порядке, определенном перечислением. Например, для DayOfWeek ключ DayOfWeek.MONDAY будет найден первым при повторении, а ключ DayOfWeek.SUNDAY будет последним.

Прочие соображения

При выборе реализации Map также учтите:

Оба эти соображения отражены в приведенной выше графической таблице.

user991710
16 февраля 2020 в 18:42
1

Поздний комментарий к ответу, который тоже опаздывает на вечеринку (но очень информативный). +1 от меня за упоминание EnumMap, так как я впервые слышу о нем. Вероятно, есть много случаев, когда это может пригодиться.

avatar
Lova Chittumuri
2 августа 2019 в 07:30
6

Использование Java 7

Map<String,String> sampleMap = new HashMap<>();
for (sampleMap.Entry<String,String> entry : sampleMap.entrySet()) {
    String key = entry.getKey();
    String value = entry.getValue();

    /* your Code as per the Business Justification  */

}

Использование Java 8

Map<String,String> sampleMap = new HashMap<>();

sampleMap.forEach((k, v) -> System.out.println("Key is :  " + k + " Value is :  " + v));
avatar
user1098063
5 июня 2019 в 19:56
6

Мне нравится объединять счетчик, а затем сохранять окончательное значение счетчика;

int counter = 0;
HashMap<String, String> m = new HashMap<String, String>();
for(int i = 0;i<items.length;i++)
{
m.put("firstname"+i, items.get(i).getFirstName());
counter = i;
}

m.put("recordCount",String.valueOf(counter));

Затем, когда вы захотите получить:

int recordCount = Integer.parseInf(m.get("recordCount"));
for(int i =0 ;i<recordCount;i++)
{
System.out.println("First Name :" + m.get("firstname"+i));
}
avatar
anandchaugule
27 ноября 2018 в 10:24
14

Эффективным итеративным решением для Map является цикл for от Java 5 до Java 7. Вот он:

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

Начиная с Java 8 вы можете использовать лямбда-выражение для итерации по карте. Это расширенный forEach

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

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

phnMap.forEach((k,v)->{
    System.out.println("Key: " + k + " Value: " + v);
    if("abc".equals(k)){
        System.out.println("Hello abc");
    }
});
avatar
Taras Melnyk
3 мая 2018 в 11:25
51

С Java 8 , вы можете перебирать Map, используя forEach и лямбда-выражение,

map.forEach((k, v) -> System.out.println((k + ":" + v)));
avatar
bluehallu
19 апреля 2018 в 12:32
24

Самый компактный с Java 8:

map.entrySet().forEach(System.out::println);
avatar
ABHAY JOHRI
17 апреля 2018 в 18:46
14

Использовать Java 8:

map.entrySet().forEach(entry -> System.out.println(entry.getValue()));
avatar
Utpal Kumar
13 ноября 2017 в 03:52
11

Есть много способов сделать это. Ниже приведены несколько простых шагов:

Предположим, у вас есть одна карта, например:

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

Затем вы можете сделать что-то вроде следующего, чтобы перебирать элементы карты.

// ********** 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));
}
avatar
shivampip
5 ноября 2017 в 14:18
11

Итерация карты очень проста.

for(Object key: map.keySet()){
   Object value= map.get(key);
   //Do your stuff
}

Например, у вас есть Map<String, int> data;

for(Object key: data.keySet()){
  int value= data.get(key);
}
michaeak
12 декабря 2018 в 12:00
2

Что ж, это излишне медленно, потому что сначала получите ключи, а затем записи. Альтернатива: получите набор записей, а затем для каждой записи установите ключ и значение.

avatar
Rupendra Sharma
6 апреля 2017 в 06:36
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));
    }
}
avatar
Witold Kaczurba
26 октября 2016 в 10:56
26

Порядок всегда будет зависеть от конкретной реализации карты. Используя Java 8, вы можете использовать любой из них:

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

Или:

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

Результат будет таким же (в том же порядке). EntitySet поддерживается картой, поэтому вы получаете тот же порядок. Второй удобен тем, что позволяет использовать лямбды, например если вы хотите печатать только целочисленные объекты, которые больше 5:

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

В приведенном ниже коде показана итерация через LinkedHashMap и обычную HashMap (пример). Вы увидите разницу в порядке:

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,
avatar
Sajad NasiriNezhad
13 апреля 2016 в 07:47
11
           //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();

            }
avatar
Slava Vedenin
22 февраля 2016 в 16:37
1400

Чтобы обобщить другие ответы и объединить их с тем, что я знаю, я нашел 10 основных способов сделать это (см. Ниже). Также я написал несколько тестов производительности (см. Результаты ниже). Например, если мы хотим найти сумму всех ключей и значений карты, мы можем написать:

  1. Использование итератора и 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. Использование foreach и Map.Entry

    long i = 0;
    for (Map.Entry<Integer, Integer> pair : map.entrySet()) {
        i += pair.getKey() + pair.getValue();
    }
    
  3. Использование для каждого из Java 8

    final long[] i = {0};
    map.forEach((k, v) -> i[0] += k + v);
    
  4. Использование keySet и для каждого

    long i = 0;
    for (Integer key : map.keySet()) {
        i += key + map.get(key);
    }
    
  5. Использование keySet и iterator

    long i = 0;
    Iterator<Integer> itr2 = map.keySet().iterator();
    while (itr2.hasNext()) {
        Integer key = itr2.next();
        i += key + map.get(key);
    }
    
  6. Использование для и 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. Использование Java 8 Stream API

    final long[] i = {0};
    map.entrySet().stream().forEach(e -> i[0] += e.getKey() + e.getValue());
    
  8. Использование Java 8 Stream API параллельно

    final long[] i = {0};
    map.entrySet().stream().parallel().forEach(e -> i[0] += e.getKey() + e.getValue());
    
  9. Использование IterableMap из Apache Collections

    long i = 0;
    MapIterator<Integer, Integer> it = iterableMap.mapIterator();
    while (it.hasNext()) {
        i += it.next() + it.getValue();
    }
    
  10. Использование MutableMap коллекций Eclipse (CS)

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

Тесты производительности (режим = AverageTime, система = Windows 8.1 64-бит, Intel i7-4790 3,60 ГГц, 16 ГБ)

  1. Для маленькой карты (100 элементов) оценка 0,308 - лучшая

    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. Для карты с 10000 элементов оценка 37,606 - лучшая

    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. Для карты со 100000 элементами оценка 1184,767 является наилучшей

    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
    

Графики (тесты производительности в зависимости от размера карты)

Enter image description here

Таблица (тесты производительности в зависимости от размера карты)

          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

Все тесты проводятся на GitHub.

GPI
12 мая 2016 в 11:53
11

@Viacheslav: очень хороший ответ. Просто интересно, как в вашем тесте API Java8 затрудняются захватом лямбда-выражений ... (например, long sum = 0; map.forEach( /* accumulate in variable sum*/); захватывает длину sum, что может быть медленнее, чем, например, stream.mapToInt(/*whatever*/).sum. Конечно, вы не всегда можете избежать захвата состояние, но это может быть разумным дополнением к скамейке запасных.

Holger
17 марта 2017 в 18:28
55

@ZhekaKozlov: посмотрите на невероятно большие значения ошибок. Учтите, что результат теста x±e подразумевает, что был результат в интервале от x-e до x+e, поэтому самый быстрый результат (1184.767±332.968) находится в диапазоне от 852 до 1518, тогда как второй самый медленный ( 1706.676±436.867) находится между 1270 и 2144, поэтому результаты по-прежнему существенно перекрываются. Теперь посмотрите на самый медленный результат, 3289.866±1445.564, который подразумевает расхождение между 1844 и 4735, и вы знаете, , что эти результаты теста бессмысленны.

Thierry
7 ноября 2017 в 23:37
8

А как насчет сравнения трех основных реализаций: HashMap, LinkedHashMap и TreeMap?

ErikE
14 июля 2018 в 19:04
18

№1 и №6 абсолютно одинаковы. Использование цикла while по сравнению с циклом for не является другим методом итерации. И я удивлен, что между ними есть такие различия в ваших тестах, что говорит о том, что тесты не изолированы должным образом от внешних факторов, не связанных с тем, что вы собираетесь тестировать.

Todd Sewell
2 января 2019 в 13:00
7

#8 - ужасный пример, поскольку из-за parallel теперь при добавлении к i возникает состояние гонки.

avatar
Syd Lambert
27 октября 2015 в 18:09
3

Если вы хотите перебирать карту в том порядке, в котором были добавлены элементы, используйте LinkedHashMap, а не просто Map.

Этот подход работал у меня в прошлом:

LinkedHashMap<String,Integer> test=new LinkedHashMap();

test.put("foo",69);
test.put("bar",1337);

for(int i=0;i<test.size();i++){
    System.out.println(test.get(test.keySet().toArray()[i]));
}

Вывод:

69
1337
avatar
Nitin Mahesh
6 октября 2015 в 15:07
37

Лямбда Выражение Java 8

В Java 1.8 (Java 8) это стало намного проще за счет использования метода forEach из агрегированных операций ( потоковых операций ), который выглядит аналогично итераторам из Iterable <3966795 > Интерфейс.

Просто скопируйте приведенную ниже инструкцию в свой код и переименуйте переменную HashMap из hm в переменную HashMap, чтобы распечатать пару ключ-значение.

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.

Ниже приведен пример кода, который я пытался использовать с лямбда-выражением . Это так круто. Обязательно попробуйте.

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

Также можно использовать Spliterator для того же.

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

ОБНОВЛЕНИЕ


Включая ссылки на документацию Oracle Docs. Для получения дополнительной информации о Lambda перейдите по этой ссылке и прочтите Агрегатные операции, а для Spliterator перейдите по этой ссылке <396674569>.

avatar
akhil_mittal
2 сентября 2015 в 01:00
37

Java 8

У нас есть метод forEach, который принимает лямбда-выражение. У нас также есть поток API. Рассмотрим карту:

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

Итерация по ключам:

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

Итерация значений:

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

Итерация по записям (с использованием forEach и 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);
        });

Преимущество потоков в том, что их можно легко распараллелить, если мы захотим. Нам просто нужно использовать parallelStream() вместо stream() выше.

forEachOrdered против forEach с потоками? forEach не следует порядку встреч (если он определен) и по своей сути недетерминирован по своей природе, в отличие от forEachOrdered. Таким образом, forEach не гарантирует, что порядок будет сохранен. Также проверьте этот, чтобы узнать больше.

avatar
tomaj
29 августа 2015 в 17:11
6

Если ваша причина для итерации через Map, заключается в том, чтобы выполнить операцию над значением и записать результат в Map. Я рекомендую использовать методы transform в классе Google Guava Maps.

import com.google.common.collect.Maps;

После того, как вы добавили Maps в свой импорт, вы можете использовать Maps.transformValues и Maps.transformEntries на своих картах, например:

public void transformMap(){
    Map<String, Integer> map = new HashMap<>();
    map.put("a", 2);
    map.put("b", 4);

    Map<String, Integer> result = Maps.transformValues(map, num -> num * 2);
    result.forEach((key, val) -> print(key, Integer.toString(val)));
    // key=a,value=4
    // key=b,value=8

    Map<String, String> result2 = Maps.transformEntries(map, (key, value) -> value + "[" + key + "]");
    result2.forEach(this::print);
    // key=a,value=2[a]
    // key=b,value=4[b]
}

private void print(String key, String val){
    System.out.println("key=" + key + ",value=" + val);
}
avatar
Joshua Michael Calafell
30 мая 2015 в 19:08
2

Я считаю, что это самый простой способ сделать это ...

/* For example, this could be a map object */
Map<String, Integer> MAP = new Map<>();

// Do something like put keys/value pairs into the map, etc...
MAP.put("Denver", 35);
MAP.put("Patriots", 14);

/* Then, simply use a for each loop like this to iterate */
for (Object o : MAP.entrySet()) {
    Map.Entry pair = (Map.Entry) o;
    // Do whatever with the pair here (i.e. pair.getKey(), or pair.getValue();
}
avatar
Mr. Polywhirl
13 мая 2015 в 12:37
7

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

import java.util.Iterator;
import java.util.Map;

public class MapUtils {
    static interface ItemCallback<K, V> {
        void handler(K key, V value, Map<K, V> map);
    }

    public static <K, V> void forEach(Map<K, V> map, ItemCallback<K, V> callback) {
        Iterator<Map.Entry<K, V>> it = map.entrySet().iterator();

        while (it.hasNext()) {
            Map.Entry<K, V> entry = it.next();

            callback.handler(entry.getKey(), entry.getValue(), map);
        }
    }

    public static <K, V> void printMap(Map<K, V> map) {
        forEach(map, new ItemCallback<K, V>() {
            @Override
            public void handler(K key, V value, Map<K, V> map) {
                System.out.println(key + " = " + value);
            }
        });
    }
}

Пример

Вот пример его использования. Обратите внимание, что тип Map определяется методом.

import java.util.*;

public class MapPrinter {
    public static void main(String[] args) {
        List<Map<?  ?>> maps = new ArrayList<Map<?  ?>>() {
            private static final long serialVersionUID = 1L;
            {
                add(new LinkedHashMap<String, Integer>() {
                    private static final long serialVersionUID = 1L;
                    {
                        put("One", 0);
                        put("Two", 1);
                        put("Three", 3);
                    }
                });

                add(new LinkedHashMap<String, Object>() {
                    private static final long serialVersionUID = 1L;
                    {
                        put("Object", new Object());
                        put("Integer", new Integer(0));
                        put("Double", new Double(0.0));
                    }
                });
            }
        };

        for (Map<?  ?> map : maps) {
            MapUtils.printMap(map);
            System.out.println();
        }
    }
}

Вывод

One = 0
Two = 1
Three = 3

Object = java.lang.Object@15db9742
Integer = 0
Double = 0.0
avatar
JohnK
10 января 2015 в 00:22
3

Это не совсем отвечает на вопрос OP, но может быть полезно другим, кто найдет эту страницу:

Если вам нужны только значения, а не ключи, вы можете сделать это:

Map<Ktype, Vtype> myMap = [...];
for (Vtype v: myMap.values()) {
  System.out.println("value: " + v);
}

Ktype, Vtype являются псевдокодами.

avatar
fechidal89
21 августа 2014 в 22:15
2

Я скопировал данные одной карты на другую с этим кодом:

HashMap product =(HashMap)shopping_truck.get(i);
HashMap tmp = new HashMap();
for (Iterator it = product.entrySet().iterator(); it.hasNext();) {
    Map.Entry thisEntry = (Map.Entry) it.next();
    tmp.put(thisEntry.getKey(), thisEntry.getValue());
}
avatar
George Siggouroglou
4 августа 2014 в 10:30
33

Java 8:

Вы можете использовать лямбда-выражения:

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

Для получения дополнительной информации следуйте этому.

humblerookie
21 августа 2014 в 19:49
0

@injecteer: Похоже, мотив лямбда-выражений

Holger
9 ноября 2016 в 12:37
9

Вам не нужен поток, если вы просто хотите перебирать карту. myMap.forEach( (currentKey,currentValue) -> /* action */ ); намного короче.

avatar
Fadid
19 марта 2014 в 17:34
16
    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());    
    }
avatar
Darshan Patel
5 февраля 2014 в 06:42
86

Есть несколько способов перебора карты.

Вот сравнение их производительности для общего набора данных, хранящегося в карте, путем сохранения миллиона пар ключевых значений в карте и итерации по карте.

1) Использование entrySet() для каждого цикла

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

50 миллисекунд

2) Использование keySet() для каждого цикла

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

76 миллисекунд

3) Использование entrySet() и итератора

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

50 миллисекунд

4) Использование keySet() и итератора

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

75 миллисекунд

Я сослался на this link.

AlexB
14 января 2019 в 13:44
1

Время выполнения взято из статьи, в которой не используется Java Microbenchmarking Harness. Поэтому время ненадежно, так как код мог, например, быть полностью оптимизирован JIT-компилятором.

avatar
Rupesh Yadav
29 января 2014 в 12:35
30

На карте можно выполнять итерацию по keys и / или values и / или both (e.g. entrySet) в зависимости от того, что вас интересует _ Например:

  1. Перебрать keys -> keySet() карты:

     Map<String, Object> map = ...;
    
     for (String key : map.keySet()) {
         //your Business logic...
     }
    
  2. Перебрать values -> values() карты:

     for (Object value : map.values()) {
         //your Business logic...
     }
    
  3. Перебрать both -> entrySet() карты:

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

Более того, существует 3 различных способа итерации через HashMap. Они следующие:

//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);
}
avatar
J.B.Vala
3 января 2014 в 12:28
6

Есть несколько способов перебрать карту. См. Следующий код.

Когда вы повторяете карту с использованием интерфейса итератора, вы должны использовать Entry<K,V> или entrySet().

Это выглядит так:

    import java.util.*;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;

    public class IteratMapDemo{

        public static void main(String arg[]){
            Map<String, String> mapOne = new HashMap<String, String>();
            mapOne.put("1", "January");
            mapOne.put("2", "February");
            mapOne.put("3", "March");
            mapOne.put("4", "April");
            mapOne.put("5", "May");
            mapOne.put("6", "June");
            mapOne.put("7", "July");
            mapOne.put("8", "August");
            mapOne.put("9", "September");
            mapOne.put("10", "Octomber");
            mapOne.put("11", "November");
            mapOne.put("12", "December");

            Iterator it = mapOne.entrySet().iterator();
            while(it.hasNext())
            {
                Map.Entry me = (Map.Entry) it.next();
                //System.out.println("Get Key through While loop = " + me.getKey());
            }
            for(Map.Entry<String, String> entry:mapOne.entrySet()){
                //System.out.println(entry.getKey() + "=" + entry.getValue());
            }

            for (Object key : mapOne.keySet()) {
                System.out.println("Key: " + key.toString() + " Value: " +
                                   mapOne.get(key));
            }
        }
    }
edin-m
29 ноября 2019 в 03:38
0

keySet () работает медленно

avatar
dmunozfer
29 ноября 2013 в 12:53
21

Если у вас есть общая нетипизированная карта, вы можете использовать:

Map map = new HashMap();
for (Map.Entry entry : ((Set<Map.Entry>) map.entrySet())) {
    System.out.println(entry.getKey() + "/" + entry.getValue());
}
avatar
The Coordinator
21 октября 2013 в 10:15
316

В Java 8 вы можете сделать это быстро и чисто, используя новые функции лямбда-выражений:

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

Типы k и v будут определены компилятором, и больше нет необходимости использовать Map.Entry.

Легко!

Vitalii Fedorenko
28 июня 2014 в 12:46
12

В зависимости от того, что вы хотите делать с картой, вы также можете использовать потоковый API для записей, возвращаемых map.entrySet().stream() docs.oracle.com/javase/8/docs/api/java/util/stream/Stream. html

Chris
20 апреля 2017 в 20:29
1

Это не сработает, если вы хотите ссылаться на неокончательные переменные, объявленные вне вашего лямбда-выражения, из forEach () ...

The Coordinator
21 апреля 2017 в 21:44
8

@ Крис Верно. Это не сработает, если вы попытаетесь использовать эффективно неокончательные переменные извне лямбда.

avatar
Pranoti
1 июля 2013 в 12:54
14

Вы можете сделать это с помощью дженериков:

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());
}
avatar
Suresh Atta
21 марта 2013 в 19:33
10

Да, как многие согласились, это лучший способ перебрать Map.

Но есть шанс выбросить nullpointerexception, если карта null. Не забудьте указать null. Отметьте.

                                                 |
                                                 |
                                         - - - -
                                       |
                                       |
for (Map.Entry<String, Object> entry : map.entrySet()) {
    String key = entry.getKey();
    Object value = entry.getValue();
}
avatar
Donald Raab
18 декабря 2012 в 23:13
43

С Коллекциями Eclipse вы должны использовать метод forEachKeyValue в интерфейсе MapIterable, который наследуется <3923596009243> интерфейсами <392359600> и их реализациями. .

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

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

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

Примечание: Я являюсь коммиттером для Eclipse Collections.

avatar
Fathah Rehman P
17 мая 2012 в 09:21
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);
        }
    }
}

ИЛИ

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();
        }
    }
}
avatar
abods
3 февраля 2010 в 06:10
29

Попробуйте это с Java 1.4:

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

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

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

  //...
}
avatar
serg
18 августа 2009 в 17:34
126

Пример использования итератора и дженериков:

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();
  // ...
}
Steve Kuo
17 февраля 2012 в 20:32
14

Вы должны поместить Iterator в цикл for, чтобы ограничить его область действия.

StudioWorks
3 февраля 2015 в 16:13
1

@SteveKuo Что вы имеете в виду, говоря «ограничить сферу охвата»?

ComFreek
13 марта 2015 в 16:33
15

@StudioWorks for (Iterator<Map.Entry<K, V>> entries = myMap.entrySet().iterator(); entries.hasNext(); ) { Map.Entry<K, V> entry = entries.next(); }. Используя эту конструкцию, мы ограничиваем область (видимость переменной) entries циклом for.

StudioWorks
13 марта 2015 в 16:59
3

@ComFreek Понятно. Не знал, что это так важно.

avatar
Chris Dail
7 сентября 2008 в 19:48
60

Правильный способ сделать это - использовать принятый ответ, поскольку он наиболее эффективен. Я считаю, что следующий код выглядит немного чище.

for (String key: map.keySet()) {
   System.out.println(key + "/" + map.get(key));
}
Jeff Olson
6 ноября 2009 в 20:46
15

Это не лучший подход, гораздо эффективнее использовать entrySet (). Findbugs отметит этот код (см. findbugs.sourceforge.net/…)

kritzikratzi
8 октября 2012 в 13:25
6

@ ДжеффОлсон, да, не совсем. поиск по карте - O (1), поэтому оба цикла ведут себя одинаково. по общему признанию, это будет немного медленнее в микробенчмарке, но я иногда делаю это, потому что ненавижу писать аргументы типа снова и снова. Кроме того, это, скорее всего, никогда не будет узким местом для вашей производительности, поэтому сделайте это, если это сделает код более читабельным.

Jeff Olson
8 октября 2012 в 17:34
0

@kritzikratzi, но с подходом entrySet () вы выполняете один поиск для каждого элемента, тогда как с подходом keySet () / get () вы выполняете два поиска для каждого элемента. Итак, теоретически (не тестировал) это O (1) против 2 * O (1). Или вдвое дольше. Правильно?

kritzikratzi
8 октября 2012 в 23:26
4

подробнее: O(1) = 2*O(1) в значительной степени является определением нотации большого O. вы правы в том, что он работает немного медленнее, но по сложности они такие же.

kornero
3 декабря 2012 в 10:43
0

Посмотрите на карту O (1), правда?))))) Где на Земле это O (1)?))) HashMap: во-первых - вы должны вычислить хеш, во-вторых - искать в массиве по хешу, в-третьих! - линейный поиск по всем элементам, имеющим одинаковый хэш-код, это называется «столкновение», разве вы не слышали об этом? =) А что вы можете сказать о: TreeMap, ConcurrentSkipListMap они тоже «O (1)»?

kritzikratzi
22 декабря 2012 в 12:29
0

@kornero хорошая точка, поиск по древовидной карте - O (log n), я имел в виду только хэш-карты (которые ~ O (1), коллизии или нет)

kornero
23 декабря 2012 в 14:30
0

Коллизии @kritzikratzi в хэш-картах создают сложность ~ O (n), и на основе этого есть "отказ в обслуживании через алгоритмические атаки сложности", вы можете узнать больше об этом здесь: cs.rice.edu/~scrosby/hash / CrosbyWallach_UsenixSec2003

kritzikratzi
23 декабря 2012 в 16:17
2

Под столкновением я имел в виду, что не имеет значения, есть ли у вас несколько столкновений, очевидно, это другая история, если у вас есть только столкновения. Итак, вы ведете себя довольно мелочно, но да, то, что вы говорите, правда.

Holger
9 ноября 2016 в 12:22
2

@ Джефф Олсон: комментарии о том, что сложность «большого О» не меняется, когда есть только постоянный коэффициент, верны. Тем не менее, для меня важно, займет ли операция час или два. Что еще более важно, необходимо подчеркнуть, что коэффициент равен , а не 2, поскольку итерация по entrySet() вообще не требует поиска; это просто линейный обход всех записей. Напротив, итерация по keySet() и выполнение поиска по каждому ключу несет один поиск по для каждого ключа, поэтому мы говорим о нулевом поиске по сравнению с n поисками здесь, n - размер Map. Значит, фактор выходит за рамки 2

Holger
9 ноября 2016 в 12:35
2

@kornero: возможно, стоит отметить, что вам не нужны ключи, чтобы иметь один и тот же хэш-код, чтобы возникла коллизия; коллизия уже существует, когда hashcode % capacity то же самое. Начиная с Java 8, сложность элементов, имеющих одинаковый hashcode % capacity, но разные hashcode или Comparable, возвращается к O(log n), и только ключи с одинаковым хэш-кодом, но не Comparable накладывают O(n) сложность. Но утверждение, что сложность поиска может быть больше O(1) на практике, все еще остается в силе.

avatar
ckpwong
5 сентября 2008 в 22:27
60

К вашему сведению, вы также можете использовать map.keySet() и map.values(), если вас интересуют только ключи / значения карты, а не другие.

avatar
serg10
5 сентября 2008 в 22:15
106

Это вопрос из двух частей:

Как перебирать записи карты - @ ScArcher2 отлично ответил на этот вопрос.

Каков порядок итерации - если вы просто используете Map, то, строго говоря, нет никаких гарантий заказа . Таким образом, вам не следует полагаться на порядок, заданный какой-либо реализацией. Однако интерфейс SortedMap расширяет Map и предоставляет именно то, что вы ищете - реализации всегда будут обеспечивать согласованный порядок сортировки.

NavigableMap - еще одно полезное расширение - это SortedMap с дополнительными методами для поиска записей по их упорядоченному положению в наборе ключей. Таким образом, потенциально это может устранить необходимость в повторении в первую очередь - вы можете найти конкретный entry, который вы используете, после использования методов higherEntry, lowerEntry, ceilingEntry или floorEntry. Метод descendingMap даже дает вам явный метод изменения порядка обхода .

avatar
Tom Hawtin - tackline
5 сентября 2008 в 21:26
143

Типичный код для итерации по карте:

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

HashMap - это реализация канонической карты, которая не дает никаких гарантий (или хотя она не должна изменять порядок, если с ней не выполняются операции изменения). SortedMap вернет записи на основе естественного порядка ключей или Comparator, если он предоставлен. LinkedHashMap будет возвращать записи либо в порядке вставки, либо в порядке доступа, в зависимости от того, как он был создан. EnumMap возвращает записи в естественном порядке ключей.

(Обновление: я думаю, что это уже неверно. ) Обратите внимание, что итератор IdentityHashMap entrySet в настоящее время имеет особую реализацию, которая возвращает один и тот же экземпляр Map.Entry для каждого элемента в <49498769 >! Однако каждый раз, когда новый итератор продвигается вперед, Map.Entry обновляется.

Premraj
10 марта 2011 в 15:41
6

EnumMap также имеет это своеобразное поведение вместе с IdentityHashMap.

jpaugh
26 января 2016 в 20:41
1

«LinkedHashMap будет либо возвращать записи в [...] порядке доступа [...]» ... чтобы вы обращались к элементам в порядке доступа к ним? Либо тавтологическое, либо что-то интересное, в котором можно сделать отступление. ;-)

Tom Hawtin - tackline
26 января 2016 в 21:24
5

@jpaugh Только прямой доступ к счетчику LinkedHashMap. Те через iterator, spliterator, entrySet и т. Д. Не изменяют порядок.

Peter Mortensen
6 февраля 2018 в 22:36
1

1. хотя если ? 2. Последний абзац можно улучшить.

avatar
Leigh Caldwell
5 сентября 2008 в 21:18
38

Теоретически наиболее эффективный способ будет зависеть от того, какая реализация Map. Официальный способ сделать это - вызвать map.entrySet(), который возвращает набор Map.Entry, каждый из которых содержит ключ и значение (entry.getKey() и entry.getValue()).

В идиосинкразической реализации может иметь значение, используете ли вы map.keySet(), map.entrySet() или что-то еще. Но я не могу придумать причину, по которой кто-то мог бы написать это так. Скорее всего, для производительности не имеет значения то, что вы делаете.

И да, порядок будет зависеть от реализации, а также (возможно) порядка вставки и других факторов, которые трудно контролировать.

[править] Первоначально я написал valueSet(), но, конечно, entrySet() - это на самом деле ответ.

avatar
pkaeding
5 сентября 2008 в 21:15
253

Да, порядок зависит от конкретной реализации карты.

@ ScArcher2 имеет более элегантный синтаксис Java 1.5. В 1.4 я бы сделал что-то вроде этого:

Iterator entries = myMap.entrySet().iterator();
while (entries.hasNext()) {
  Entry thisEntry = (Entry) entries.next();
  Object key = thisEntry.getKey();
  Object value = thisEntry.getValue();
  // ...
}
jai
20 октября 2009 в 13:20
45

Предпочитайте цикл for, чем while .. for (Iterator entries = myMap.entrySet (). Iterator (); entries.hasNext ();) {...} Благодаря этому синтаксису область 'записей' сокращается только до цикла for .

pkaeding
10 января 2012 в 15:42
8

@jpredham Вы правы в том, что использование конструкции for в качестве for (Entry e : myMap.entrySet) не позволит вам изменять коллекцию, но в примере как @HanuAthena упоминается, что она должна работать, поскольку дает вам Iterator в области видимости. (Если я чего-то не упускаю ...)

JohnK
10 января 2015 в 00:06
1

IntelliJ выдает ошибки на Entry thisEntry = (Entry) entries.next();: не распознает Entry. Этот псевдокод для чего-то другого?

pkaeding
14 января 2015 в 02:35
1

@JohnK попробуйте импортировать java.util.Map.Entry.

user5778069
21 января 2017 в 08:09
1

Это решение не будет работать, если у вас есть целочисленный ключ и строковый ключ.