web-dev-qa-db-ja.com

HashMapの値をループするために、Javaでforeachループを使用するにはどうすればよいですか?

私は次のコードをコンパイルしようとしています:

_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行に次のようなエラーが表示されます。

互換性のないタイプ
 found:Java.lang.Object 
 required:MyClass.Key 

getData()メソッドはObjectを返します(ただし、この場合、返されるObjectHashMap構造を持ちます)。 _MyClass.Key_は、アプリケーションの目的のために作成した列挙型です(別のクラスファイル-MyClass)。

_MyClass.Java_で同じ構造を持つforeachループを作成したとき、この問題は発生しませんでした。

私は何を間違えていますか?

37
troyal

これを行うより少し効率的な方法:

  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」を定義します。

42
Paul Tomblin

変化する:

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

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

問題は、データが単なるMapの場合、data.keySet()が_Collection<Object>_を返すことです。汎用化すると、keySet()は_Collection<MyClass.Key>_を返します。さらに良い... entrySet()を反復処理します。これは_Collection<MyClass.Key, String>_になります。余分なハッシュルックアップを回避します。

38
Craig P. Motlin

Javaフォーラム でこの簡単な例を見つけました。その構文は、リストのforeachと非常に似ており、私が探していたものでした。

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

[編集:]私はそれをテストし、完全に動作します。

5
dialex

代わりに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;
}
4

モトリンの答えは正しいです。

2つのメモがあります...

  1. toString += ...を使用せず、代わりにStringBuilderを使用してデータを追加します。

  2. Martinが提案したキャストでは、未チェックの警告が表示されますが、これは本当に安全ではないため、取り除くことはできません。

別の方法、警告なし(および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();
}

keyで呼び出すtoStringメソッドはObjectクラスで定義されているため、これは機能します。したがって、キャストする必要はまったくありません。

entrySetを使用すると、マップで別のルックアップを行う必要がないため、さらに良い方法です。

3