web-dev-qa-db-fra.com

Comment utiliser une boucle foreach dans Java pour parcourir les valeurs d'un HashMap?

J'essaie de compiler le code suivant:

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

J'obtiens une erreur dans la ligne for qui dit:

 types incompatibles 
 trouvés: Java.lang.Object 
 requis: MyClass.Key 

La méthode getData() renvoie un Object (mais dans ce cas, le Object retourné a la structure HashMap). MyClass.Key Est une énumération que j'ai créée pour les besoins de mon application (dans un autre fichier de classe - MyClass).

Lorsque j'ai créé une boucle foreach avec la même structure dans MyClass.Java, Je n'ai pas rencontré ce problème.

Qu'est-ce que je fais mal?

37
troyal

Une façon un peu plus efficace de le faire:

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

Si possible, définissez "getData" afin de ne pas avoir besoin du cast.

42
Paul Tomblin

Changement:

Map data = (HashMap<MyClass.Key, String>) getData();

à

Map<MyClass.Key, String> data = (HashMap<MyClass.Key, String>) getData();

Le problème est que data.keySet() retourne un Collection<Object> Si les données ne sont qu'un Map. Une fois générique, keySet() renverra un Collection<MyClass.Key>. Encore mieux ... parcourez la entrySet(), qui sera un Collection<MyClass.Key, String>. Cela évite les recherches de hachage supplémentaires.

38
Craig P. Motlin

J'ai trouvé cet exemple simple sur forum Java . Sa syntaxe est très similaire à foreach de la liste , ce que je cherchais.

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:] Je l'ai testé et cela fonctionne parfaitement.

5
dialex

Vous pouvez saisir le entrySet à la place, pour éviter d'avoir besoin de la classe de clé:

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;
}
4
Richard Campbell

La réponse de Motlin est correcte.

J'ai deux notes ...

  1. N'utilisez pas toString += ..., mais utilisez StringBuilder à la place et ajoutez-y des données.

  2. Le casting que Martin a suggéré vous donnera un avertissement non contrôlé, dont vous ne pourrez pas vous débarrasser, car il est vraiment dangereux.

Une autre façon, sans avertissement (et avec 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();
}

Cela fonctionne, car la méthode toString que vous appelez key est définie dans la classe Object, vous n'avez donc pas besoin du tout de transtyper.

Utiliser entrySet est encore mieux, car il n'a pas besoin de faire une autre recherche dans la carte.

3
Peter Štibraný