Iterando por um HashMap em Java
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.