Iterando por um HashMap em Java

Iterando por um HashMap em Java
Imagem de destaque #cover

Estamos desenvolvendo um sistema web para uma empresa de ensino online. Nesse sistema é necessário que o usuário preencha um cadastro inicial, nada muito trabalhoso, apenas o nome, data de nascimento e o estado onde ele reside.

Temos o seguinte formulário de cadastro:

Mas se abrirmos a lista de opções de estados temos o seguinte resultado:

Ele está vazio. Não é isso que queremos. Queremos que quando o usuário abrir a lista de opções a mesma esteja preenchida com as siglas dos estados. Algo assim:

Temos um HashMap com as siglas e os estados e queremos usar para conseguir preencher nosso formulário. Esse HashMap foi feito através do seguinte método:


public HashMap<String, String> getMapa() { 
HashMap<String, String> map = new HashMap<>(); 
map.put("AC", "Acre"); map.put("AL", "Alagoas");
map.put("AP", "Amapá"); map.put("AM", "Amazonas");
map.put("BA", "Bahia"); map.put("CE", "Ceará"); 
map.put("DF", "Distrito Federal"); map.put("ES", "Espírito Santo"); 
map.put("GO", "Goiás"); 
//resto dos put() 
return map; }

Para conseguir retornar apenas as siglas, ou seja, as chaves, vamos usar o método keySet() da classe Map. Ele nos devolve um Set, que, basicamente, é uma coleção de elementos únicos, logo, não se repetem.

Agora vamos iterar sobre o retorno desse método para vermos se nosso método está realmente retornando todas as siglas:


HashMap<String, String> mapaEstados = getMapa(); 
for (String sigla : mapaEstados.keySet()) { System.out.print(sigla + " "); }

Ao executar esse código, obtemos o seguinte resultado:

Funcionou! Mas como faríamos para mostrar esse resultado na web?

Podemos usar uma JSP. Para conseguir o resultado esperado, só precisamos iterar os valores, desse jeito:

 <c:forEach items="${mapaEstados.keySet()}" 
 var="sigla"> <option>${sigla}</option> 
 </c:forEach>

E aí, visualizando o formulário:

Uma outra abordagem muito comum é o value da tag option ser a sigla, mas exibir o nome do estado por extenso. Ou seja, por exemplo, o value ser SP, só que o usuário veria São Paulo. Vamos tentar fazer isso?

Para alcançar tal resultado, precisamos tanto da chave quanto do valor do mapa. Para conseguirmos ambos, podemos usar o método entrySet() da classe Map. Ele nos devolve um Set<Map.Entry<K, V>>, onde K e V são os tipos da chave e do valor respectivamente do nosso mapa. Esse retorno nada mais é do que uma entrada contendo a chave e seu respectivo valor.

Vamos iterar esse entrySet():


for (Map.Entry<String, String> entrada : mapaEstados.entrySet()) {
     System.out.println(entrada); 
}

Como resultado desse código, temos o seguinte:

Mas perceba que essa forma não é ideal, pois não conseguimos manusear de forma eficaz a chave e o valor. Conseguimos, apenas, a entrada inteira e ainda com um sinal de igual horrível no meio. Para resolve isso, vamos usar os métodos getKey() e getValue() de Map.Entry:


HashMap<String, String> mapaEstados = getMapa(); 
for (Map.Entry<String, String> entrada : mapaEstados.entrySet()) { 
System.out.println(entrada.getKey()); 
System.out.println(entrada.getValue());
}

E como resultado, temos:

Cada chave está associada ao seu valor, está tudo correto. Agora, se fossemos implementar na JSP, teríamos que usar os métodos na JSP. Dessa forma:


<c:forEach items="${mapaEstados.entrySet()}" 
var="entrada"> <option value="${entrada.key}">${entrada.value}
</option> 
</c:forEach>

Se olharmos o código html, temos o seguinte: <select> <option value="RR">Boa Vista</option> <option value="RS">Porto Alegre</option><br /> <option value="DF">Brasília</option> //outros options </select>

Perceba que está exatamente do jeito que queríamos, o value é a sigla e para o usuário aparece os estados por extenso.

Se quiséssemos apenas os estados por extenso para o usuário escolher, sem precisar atribuir a chave como o value da tag option, poderíamos usar o método values() que retorna uma coleção contendo os valores do mapa. Assim:


HashMap<String, String> mapaEstados = getMapa();
 for (String valor : mapaEstados.values()) { 
     System.out.println(valor); 
}

Ao executar esse código:

Agora na JSP:


<c:forEach items="${mapaEstados.values()}" 
var="estado"> <option>${estado}</option> 
</c:forEach>

Voltando ao primeiro exemplo, caso nossa lista de estados contivesse apenas as siglas e, em outra tela, por exemplo uma tela de confirmação, onde mostrasse os dados que o usuário preencheu, quiséssemos mostrar o estado por extenso referente a sigla que o usuário escolheu, como faríamos?

Podemos criar um método que recebe como parâmetro a sigla escolhida e usar o método get() da interface Map para pegar seu respectivo valor. Dessa forma:


public static String pegaEstadoPorExtenso(String sigla){ 
HashMap<String, String> mapa = getMapa(); 
return mapa.get(sigla);
}

Para testarmos, vamos mandar a sigla RJ:


System.out.println(pegaEstadoPorExtenso("RJ"));

O resultado é exatamente o que esperamos:

Desenvolvemos tudo o que foi pedido de forma eficiente e limpa, parabéns!

Para saber mais

Todas as iterações que fizemos para testar nossos métodos poderiam ter sido feitas usando programação funcional, uma feature trazida com o Java 8. Por exemplo, para imprimir as siglas:


mapaEstados.keySet().stream().forEach(System.out::println);

Para imprimir as chaves e os valores:


mapaEstados.forEach((sigla, estado) -> System.out.println(sigla + " " + estado));

E por fim, os valores usando o values()


mapaEstados.values().stream().forEach(System.out::println);

Se quiser conhecer mais sobre as milhares de funcionalidades trazidas pelo Java 8 confira o curso Java 8: Tire proveito dos novos recursos da linguagem da Alura.

Quer dominar de vez mapas e coleções? Aqui na Alura temos uma formação em Java. Lá é mostrado a fundo cada coleção e, também, possui um capítulo só sobre mapas. Vale muito a pena dar uma conferida.

Veja outros artigos sobre Programação