Как использовать цикл foreach в Java для циклического перебора значений в HashMap? - PullRequest
37 голосов
/ 15 января 2009

Я пытаюсь скомпилировать следующий код:

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

В строке for появляется сообщение об ошибке:

incompatible types
found : java.lang.Object
required: MyClass.Key

Метод getData() возвращает Object (но в этом случае возвращенный Object имеет структуру HashMap). MyClass.Key - это перечисление, которое я создал для целей моего приложения (в другом файле класса - MyClass).

Когда я создал цикл foreach с такой же структурой в MyClass.java, я не столкнулся с этой проблемой.

Что я делаю не так?

Ответы [ 5 ]

42 голосов
/ 15 января 2009

Несколько более эффективный способ сделать это:

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

Если это вообще возможно, определите «getData», чтобы вам не понадобилось приведение.

38 голосов
/ 15 января 2009

Изменение:

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

до

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

Проблема в том, что data.keySet() возвращает Collection<Object>, если данные просто Map. Как только вы сделаете его общим, keySet() вернет Collection<MyClass.Key>. Еще лучше ... перебрать entrySet(), который будет Collection<MyClass.Key, String>. Это позволяет избежать дополнительных поисков по хешу.

5 голосов
/ 20 апреля 2011

Я нашел этот простой пример на форуме java . Его синтаксис очень похож на foreach в List , который я искал.

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

[РЕДАКТИРОВАТЬ:] Я проверил его, и он отлично работает.

4 голосов
/ 15 января 2009

Вместо этого вы можете получить entrySet, чтобы не нуждаться в классе ключа:

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;
}
3 голосов
/ 15 января 2009

Мотлин ответил правильно.

У меня есть две заметки ...

  1. Не используйте toString += ..., а используйте StringBuilder и добавляйте к нему данные.

  2. Состав, предложенный Мартином, выдаст вам непроверенное предупреждение, от которого вы не сможете избавиться, потому что это действительно небезопасно.

Другой способ, без предупреждения (и с 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();
}

Это работает, потому что метод toString, который вы вызываете для key, определен в классе Object, поэтому вам вообще не нужно приводить.

Использование entrySet - еще лучший способ, так как не нужно делать еще один поиск на карте.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...