Como faço para usar um loop foreach em Java para percorrer os valores em um HashMap?
Pergunta
Estou tentando compilar o código a seguir:
private String dataToString(){
Map data = (HashMap<MyClass.Key, String>) getData();
String toString = "";
for( MyClass.Key key: data.keySet() ){
toString += key.toString() + ": " + data.get( key );
return toString;
}
Eu recebo um erro no para a linha que diz:
incompatible types found : java.lang.Object required: MyClass.Key
O método getData()
retorna um Object
(mas, neste caso, o Object
devolvido tem a estrutura HashMap
). MyClass.Key
é uma enumeração que eu criei para os fins do meu aplicativo (em outro arquivo de classe - MyClass
).
Quando eu criei um laço foreach com a mesma estrutura em MyClass.java
, eu não encontrar esse problema.
O que estou fazendo de errado?
Solução
Uma maneira um pouco mais eficiente de fazer isso:
Map<MyClass.Key, String> data = (HashMap<MyClass.Key, String>) getData();
StringBuffer sb = new StringBuffer();
for (Map.Entry<MyClass.Key,String> entry : data.entrySet()) {
sb.append(entry.getKey());
sb.append(": ");
sb.append(entry.getValue());
}
return sb.toString();
Se possível, definir "getData" para que você não precisa do elenco.
Outras dicas
Alterar:
Map data = (HashMap<MyClass.Key, String>) getData();
para
Map<MyClass.Key, String> data = (HashMap<MyClass.Key, String>) getData();
O problema é que data.keySet()
retorna um Collection<Object>
se os dados é apenas um Map
. Uma vez que você torná-lo genérico, keySet()
retornará um Collection<MyClass.Key>
. Ainda melhor ... iterar sobre os entrySet()
, que será um Collection<MyClass.Key, String>
. Evita as pesquisas de hash extra.
Eu encontrei este exemplo simples em java fórum . Seu sintaxe é muito semelhante ao foreach da List , que era o que eu estava procurando.
import java.util.Map.Entry;
HashMap nameAndAges = new HashMap<String, Integer>();
for (Entry<String, Integer> entry : nameAndAges.entrySet()) {
System.out.println("Name : " + entry.getKey() + " age " + entry.getValue());
}
[EDIT:]. Eu testei e ele funciona perfeitamente
Você poderia pegar o entrySet em vez disso, para evitar a necessidade da classe chave:
private String dataToString(){
Map data = (HashMap<MyClass.Key, String>) getData();
String toString = "";
for( Map.Entry entry: data.entrySet() ) {
toString += entry.getKey() + ": " + entry.getValue();
}
return toString;
}
A resposta de Motlin está correto.
Eu tenho duas notas ...
-
Não use
toString += ...
, mas o usoStringBuilder
vez e acrescentar dados a ele. -
Elenco qual Martin sugeriu lhe dará aviso desmarcada, que você não será capaz de se livrar, porque é realmente inseguro.
Outra maneira, sem aviso (e com StringBuilder):
private String dataToString(){
Map<?, ?> data = (Map<?, ?>) getData();
StringBuilder toString = new StringBuilder();
for (Object key: data.keySet()) {
toString.append(key.toString());
toString.append(": ");
toString.append(data.get(key));
}
return toString.toString();
}
Isso funciona, porque o método toString que você chama em key
é definido na classe Object, então você não precisa de fundição em tudo.
Usando entrySet
é ainda melhor maneira, uma vez que não precisa fazer um outro olhar-se no mapa.