Pergunta sobre iteration, java, loops, hashmap – Iterar através de um HashMap [duplicado]

3059

Duplicata Possível:
Como iterar eficientemente sobre cada entrada em um 'Mapa'?

Qual é a melhor maneira de iterar os itens em umHashMap?

Verifique a resposta:stackoverflow.com/a/53497541/5756557 anandchaugule
Eu preciso pegar as chaves e valores e adicioná-los a um array multidimensional burntsugar
No Java 8 usando o Lambda Expression:stackoverflow.com/a/25616206/1503859 Nitin Mahesh
Como isso tem uma pontuação maior do que a questão de uma duplicata? immibis
@immibis provavelmente porque muitas pessoas usam instintivamente o HashMaps sem considerar outras implementações de mapas. Então, quando eles inevitavelmente ficam presos tentando fazer uma iteração em seu HashMap, eles fazem "Iterar através de um HashMap" para o Google, levando-os diretamente para cá. Dean Wild

Sua resposta

7   a resposta
787

Como Iterar um Mapa em Java:

Existem várias maneiras de iterar sobre umMap em Java. Vamos examinar os métodos mais comuns e revisar suas vantagens e desvantagens. Como todos os mapas em Java implementam a interface Map, as técnicas a seguir funcionarão para qualquer implementação de mapa (HashMap, TreeMap, LinkedHashMap, Hashtableetc.)

Método 1: Iterando entradas usando um loop For-Each.

Este é o método mais comum e é preferível na maioria dos casos. Ele deve ser usado se você precisar das chaves do mapa e dos valores no loop.

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

Observe que o loop For-Each foi introduzido no Java 5, portanto, esse método está funcionando apenas em versões mais recentes da linguagem. Também um loop For-Each lançaráNullPointerException Se você tentar iterar em um mapa que é nulo, então antes de iterar você deve sempre verificar se há referências nulas.

Método 2: Iterando chaves ou valores usando um loop For-Each.

Se você precisar apenas de chaves ou valores do mapa, poderá iterar sobre keySet ou valores em vez de 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);
}

Este método oferece uma pequena vantagem de desempenhoentrySet iteração (cerca de 10% mais rápida) e é mais limpo.

Método 3: Iterando usando Iterator.

Usando genéricos:

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

Sem genéricos:

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

Você também pode usar a mesma técnica para iterarkeySet ou valores.

Esse método pode parecer redundante, mas tem suas próprias vantagens. Primeiro de tudo, é a única maneira de iterar em um mapa em versões mais antigas do Java. A outra característica importante é que é o único método que permite remover entradas do mapa durante a iteração chamandoiterator.remove(). Se você tentar fazer isso durante a iteração For-Each, obterá "resultados imprevisíveis" de acordo comJavadoc.

Do ponto de vista do desempenho, esse método é igual a uma iteração For-Each.

Método 4: Iterando chaves e procurando por valores (ineficientes).

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

Isso pode parecer uma alternativa mais limpa para o método 1, mas na prática é bastante lento e ineficiente, pois a obtenção de valores por uma chave pode ser demorada (esse método em diferentes implementações de mapa é 20% -200% mais lento que o método # 1 ). Se você tiver o FindBugs instalado, ele irá detectar isso e avisar sobre a iteração ineficiente. Esse método deve ser evitado.

Conclusão:

Se você precisar apenas de chaves ou valores do mapa, use o método # 2. Se você estiver preso a uma versão mais antiga do Java (menos de 5) ou planejando remover entradas durante a iteração, será necessário usar o método # 3. Caso contrário, use o método # 1.

@ohbrobig ainda é O (1) mas esse é o tempo de execução, é assim que é escalável. Isso não significa que necessariamente terá o valor no primeiro ciclo. O método 4 será definitivamente mais lento que o método # 1. user961954
@arvind Como o método 4 nunca seria ineficiente? Por definição, chamarget() é sempre O (1) para um HashMap. Essa é a definição de um HashMap e o usuário solicitou um HashMap. Eu não entendo porque isso é tão altamente votado. Se você for referenciar o link de outra pessoa, verifique se ela realmente faz sentido para a pergunta. ohbrobig
Vamos adicionar o pequeno caevet, que em caso deConcurrentMaps, iteração emkeySet() irá falhar em geral (não há garantia de que os valores existam para chaves obtidas anteriormente). Por outro lado, usar iteradores ou entradas é seguro (eles sempre se referem a objetos existentes). P Marecki
43

ada, vá até oentrySet. Se você só precisa dos valores, então há ovalues() método. E se você só precisa das chaves, então usekeyset().

Uma prática ruim seria fazer uma iteração em todas as chaves e, em seguida, dentro do loop, sempre façamap.get(key) para obter o valor. Se você está fazendo isso, então a primeira opção que escrevi é para você.

Mais um ponto importante, o Conjunto retornado por keySet () e Coleção retornados por valores () são ambos suportados pelo Mapa original. Ou seja, se você fizer alguma modificação neles, eles serão refletidos no Mapa, no entanto, os dois não suportam os métodos add () e addAll (), ou seja, você não pode adicionar uma nova chave ao Set ou ao novo valor. na coleção. sactiw
4383

pode percorrer o caminhokeySet() do mapa:

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

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

Se você precisar apenas dos valores, usevalues():

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

Finalmente, se você quer a chave e o valor, useentrySet():

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

Uma ressalva: se você quiser remover itens no meio da iteração, você precisará fazê-lo através de um Iterador (verResposta de karim79). No entanto, alterar os valores dos itens é OK (consulteMap.Entry).

@MarcoSulla Perguntas de desempenho como essa dependem, você deve medir e ver nos casos que importam. É provável que usandoentrySet é mais rápido porque pode evitar fazer uma pesquisa para cada entrada. A implementação do particularMap determina qual é o melhor e quanto custa. A pressão do GC naquele ponto também poderia ser um fator. doug65536
Eu recebo e tipos incompatíveis de erro para 'entrada Map.Entry' e 'Map.Entry <Integer, HashMap> entrada: "Objeto necessário, encontrado Entrada". Estou mapeando inteiros para hashmaps. Ter que usar o conjunto de chaves para loop por causa disso e puxar o valor através de 'value = (HashMap) integertomap.get (key)', embora menos eficiente, em seguida, se eu pudesse usar entrySet sem iterater como por seu exemplo. Androidcoder
Desde mapa não vem sobIterador classe como na primeira solução a pessoa usou o iterador? Rishabh Agarwal
Sobre obter valores e chaves, não é apenas mais simples usar o primeiroforeach exemplo e obter o valor dentro do loop, comvalue = map.get(key)? É o desempenho deentrySet mais alto? Marco Sulla
115
for (Map.Entry<String, String> item : hashMap.entrySet()) {
    String key = item.getKey();
    String value = item.getValue();
}
@ChanjungKim sim, é o nome do HashMap heman123
Param o nome do HashMap? c-an
85

Você pode percorrer as entradas em umMap em várias formas. Obtenha cada chave e valor assim:

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

Ou você pode obter a lista de chaves com

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

Se você quiser apenas obter todos os valores e não se preocupar com as chaves, poderá usar:

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

Iterar através doentrySet() igual a:

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
    }
}

Leia mais sobreMap.

Eu considero que a resposta do arvnid, apesar de ser apenas uma cópia / colar ou não. (Concordo que é ético dar os devidos créditos àquele que pertence) Victor
A interface do iterador é genérica desde 1.2. Precisa ser o Iterador <E> etlds
@vimukthi o que você quer dizer com uma solução para isso? Basta remover oit.remove(); linha. Danny
Eu considero isso uma resposta ruim. OP estava pedindo apenas para iterar sobre o mapa, não como modificar o mapa durante a iteração. Mader Levap
60

Mais esperto:

for (String key : hashMap.keySet()) {
    System.out.println("Key: " + key + ", Value: " + map.get(key));
}
map.entrySet () que retorna entradas que já contêm a chave e o valor. Dessa forma, você não precisa chamar hashCode () e pesquisar o hash durante a iteração. ComputerEngineer88
map.get (key) para cada iteração não é mais inteligente - é mais lento ComputerEngineer88
Sintaxe do Java 8. Pode ainda não funcionar para o desenvolvimento do Android. "O Android não se destina a ser 100% compatível com qualquer versão da API Java SE, nem 6 nem 8 nem nenhum. ... O JRE é o Java Runtime Environment, enquanto o JDK é o Java Development Kit. É o JDK que você precisa para desenvolvimento de aplicativos Android junto com o SDK do Android existente. 9 de dezembro de 2013 "fonte jasonleonhard
isso realmente depende se você precisa ou não das chaves. se não, é mais eficiente usar entrySet () como hashCode () não é chamado. icfantv

Perguntas relacionadas