Как эффективно перебрать каждую запись на карте Java? - PullRequest
2938 голосов
/ 06 сентября 2008

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

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

Ответы [ 38 ]

32 голосов
/ 19 декабря 2012

С коллекциями Eclipse (ранее коллекции GS ) вы использовали бы метод forEachKeyValue в интерфейсе MapIterable , который наследуется интерфейсами MutableMap и ImmutableMap и их реализации.

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

С помощью лямбда-синтаксиса Java 8 вы можете написать код следующим образом:

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

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

28 голосов
/ 06 сентября 2008

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

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

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

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

27 голосов
/ 04 августа 2014

Java 8:

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

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

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

26 голосов
/ 03 февраля 2010

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

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

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

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

  //...
}
26 голосов
/ 03 мая 2018

С Java 8

map.forEach((k, v) -> System.out.println((k + ":" + v)));
26 голосов
/ 02 сентября 2015

Java 8

У нас есть forEach метод, который принимает лямбда-выражение . У нас также есть stream 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 не гарантирует, что заказ будет сохранен. Также проверьте это для более.

25 голосов
/ 06 октября 2015

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

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

Просто скопируйте оператор вставки ниже в свой код и переименуйте переменную 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();

UPDATE


Включая ссылки на документацию по Oracle Docs. Для получения дополнительной информации по Lambda перейдите по этой ссылке и должны прочитать Совокупные операции , а для Spliterator перейдите по этой ссылке .

23 голосов
/ 29 января 2014

В карте можно выполнять итерации по 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);
}
18 голосов
/ 17 мая 2012
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);
        }
    }
}

OR

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();
        }
    }
}
18 голосов
/ 19 апреля 2018

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

map.entrySet().forEach(System.out::println);
...