Итерация по HashMap

2987

Возможный дубликат:
Как эффективно перебрать каждую запись в "карте"?

Какой лучший способ перебрать элементы в HashMap?

  • 3
    Мне нужно получить ключи и значения и добавить их в многомерный массив
  • 19
    Как это имеет более высокий балл, чем вопрос, дубликат которого?
Показать ещё 3 комментария
Теги:
loops
hashmap
iteration

7 ответов

3101
Лучший ответ

entrySet() по entrySet() примерно так:

public static void printMap(Map mp) {
    Iterator it = mp.entrySet().iterator();
    while (it.hasNext()) {
        Map.Entry pair = (Map.Entry)it.next();
        System.out.println(pair.getKey() + " = " + pair.getValue());
        it.remove(); // avoids a ConcurrentModificationException
    }
}

Узнайте больше о Map.

  • 33
    Несмотря на старый стиль, это поможет избежать исключений ConcurrentModificationException по сравнению с новым стилем foreach в ответах ниже. Например, вы можете удалить через отдельный итератор.
  • 422
    @ karim79 Что вы думаете о следующем пути: Map<Integer, Integer> map = new HashMap<Integer, Integer>(); for (Map.Entry<Integer, Integer> entry : map.entrySet()) { System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue()); }
Показать ещё 24 комментария
4516

Если вас интересуют только ключи, вы можете перебирать keySet() на карте:

Map<String, Object> map = ...;

for (String key : map.keySet()) {
    // ...
}

Если вам нужны только значения, используйте values():

for (Object value : map.values()) {
    // ...
}

Наконец, если вы хотите как ключ, так и значение, используйте entrySet():

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

Одно предостережение: если вы хотите удалить элементы средней итерации, вам нужно сделать это через Iterator (см. ответ karim79). Однако изменение значений элементов в порядке (см. Map.Entry).

  • 3
    Так как же сделать цикл по 2 картам одновременно? используя метод entrySet? Я пытался использовать &&, но это не работает
  • 2
    Используйте два итератора. Смотрите принятый ответ, например, использование итератора.
Показать ещё 6 комментариев
808

Извлечен из ссылки Итерация по карте в Java:

В Java существует несколько способов итерации по Map. Давайте рассмотрим наиболее распространенные методы и рассмотрим их преимущества и недостатки. Поскольку все карты в Java реализуют интерфейс Map, для любой реализации карты будут использоваться следующие методы (HashMap, TreeMap, LinkedHashMap, Hashtable и т.д.)

Метод # 1: Итерирование записей с использованием цикла For-Each.

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

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

Обратите внимание, что цикл For-Every был введен в Java 5, поэтому этот метод работает только в более новых версиях языка. Также цикл For-Each будет бросать NullPointerException, если вы попытаетесь выполнить итерацию по карте, которая равна null, поэтому перед итерацией вы всегда должны проверять наличие нулевых ссылок.

Метод # 2: Итерирование по ключам или значениям с использованием цикла For-Each.

Если вам нужны только ключи или значения с карты, вы можете выполнять итерацию по набору ключей или значениям вместо entrySet.

Map<Integer, Integer> map = new HashMap<Integer, Integer>();

// Iterating over keys only
for (Integer key : map.keySet()) {
    System.out.println("Key = " + key);
}

// Iterating over values only
for (Integer value : map.values()) {
    System.out.println("Value = " + value);
}

Этот метод дает небольшое преимущество в производительности по сравнению с entrySet итерацией (примерно на 10% быстрее) и более чистым.

Метод # 3: Итерация с использованием Iterator.

Использование дженериков:

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

Без Generics:

Map map = new HashMap();
Iterator entries = map.entrySet().iterator();
while (entries.hasNext()) {
    Map.Entry entry = (Map.Entry) entries.next();
    Integer key = (Integer)entry.getKey();
    Integer value = (Integer)entry.getValue();
    System.out.println("Key = " + key + ", Value = " + value);
}

Вы также можете использовать один и тот же метод для итерации по keySet или значениям.

Этот метод может выглядеть излишним, но он имеет свои преимущества. Прежде всего, это единственный способ перебора карты в более старых версиях Java. Другая важная особенность заключается в том, что это единственный метод, который позволяет удалять записи с карты во время итерации, вызывая iterator.remove(). Если вы попытаетесь сделать это во время каждой итерации, вы получите "непредсказуемые результаты" в соответствии с Javadoc.

С точки зрения производительности этот метод равен Итерации For-Each.

Метод # 4: Итерирование по клавишам и поиск значений (неэффективно).

Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (Integer key : map.keySet()) {
    Integer value = map.get(key);
    System.out.println("Key = " + key + ", Value = " + value);
}

Это может выглядеть как более чистая альтернатива для метода № 1, но на практике это довольно медленно и неэффективно, так как получение значений с помощью ключа может занять много времени (этот метод в разных реализациях Map на 20% -200% медленнее, чем метод № 1). Если у вас установлен FindBugs, он обнаружит это и предупредит вас о неэффективной итерации. Этот метод следует избегать.

Вывод:

Если вам нужны только ключи или значения с карты, используйте метод # 2. Если вы застряли со старой версией Java (менее 5) или планируете удалять записи во время итерации, вы должны использовать метод # 3. В противном случае используйте метод # 1.

  • 1
    Добавим небольшую подсказку, что в случае с ConcurrentMap итерация по keySet() в целом keySet() нет гарантии, что значения существуют для ранее собранных ключей). С другой стороны, использование итераторов или записей безопасно (они всегда ссылаются на существующие объекты).
  • 2
    @arvind Как метод № 4 может быть неэффективным? По определению, вызов get() всегда является O (1) для HashMap. Это определение HashMap, и пользователь запросил HashMap. Я не понимаю, почему это так высоко проголосовало. Если вы собираетесь ссылаться на чужую ссылку, убедитесь, что она действительно имеет смысл для задаваемого вопроса.
101
for (Map.Entry<String, String> item : params.entrySet()) {
    String key = item.getKey();
    String value = item.getValue();
}
  • 0
    Является ли param именем HashMap?
  • 0
    @ChanjungKim да, это имя HashMap
79

Вы можете перебирать записи на Map несколькими способами. Получите каждый ключ и значение следующим образом:

Map<?,?> map = new HashMap<Object, Object>();
for(Entry<?, ?> e: map.entrySet()){
    System.out.println("Key " + e.getKey());
    System.out.println("Value " + e.getValue());
}

Или вы можете получить список ключей с

Collection<?> keys = map.keySet();
for(Object key: keys){
    System.out.println("Key " + key);
    System.out.println("Value " + map.get(key));
}

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

Collection<?> values = map.values();
57

Smarter:

for (String key : hashMap.keySet()) {
    System.out.println("Key: " + key + ", Value: " + map.get(key));
}
  • 8
    на самом деле это зависит от того, нужны ли вам ключи. если нет, то более эффективно использовать entrySet (), поскольку hashCode () не вызывается.
  • 14
    map.get (key) для каждой итерации не умнее - она медленнее
Показать ещё 2 комментария
44

Зависит. Если вы знаете, что вам понадобится как ключ, так и значение каждой записи, перейдите к entrySet. Если вам нужны только значения, то существует метод values(). И если вам просто нужны ключи, используйте keyset().

Плохая практика заключалась бы в том, чтобы перебирать все ключи, а затем в цикле всегда делать map.get(key) для получения значения. Если вы это делаете, то первый вариант, который я написал, для вас.

  • 1
    Еще один важный момент: Set, возвращаемый keySet (), и Collection, возвращаемый values (), поддерживаются исходной картой. То есть, если вы внесете в них какие-либо изменения, они будут отражены обратно на карте, однако оба они не поддерживают методы add () и addAll (), т. Е. Вы не можете добавить новый ключ в Set или новое значение. в коллекции.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню