Soru HashMap'teki değerler arasında dolaşmak için Java'da bir foreach döngüsünü nasıl kullanırım?


Aşağıdaki kodu derlemeye çalışıyorum:

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

Şu satırda hata mesajı alıyorum:

uyumsuz türler
Bulunan: java.lang.Object
gerekli: MyClass.Key

getData() yöntem bir döndürür Object (ama bu durumda Object geri döndü HashMap yapı). MyClass.Key başvurumun amaçları için oluşturduğum bir enum (başka bir sınıf dosyasında) MyClass).

Aynı yapıya sahip bir foreach döngüsü oluşturduğumda MyClass.javaBu problemle karşılaşmadım.

Neyi yanlış yapıyorum?


36
2018-01-15 19:30


Menşei


Yalnızca bir Haritaya atayacağınız bir HashMap'e getData () atmaya gerek yoktur. Bunun yerine bir Harita. GetData (), HashMap olmayan (TreeMap gibi) döndürürse ne olur? - Steve Kuo
Ben aslında burada bazı bilgiler dışarıda bıraktım ... getData () aslında getData (String tuşu), nerede anahtar almak istediğiniz istenen Object belirtir. Yani, aldığım nesneyi tanıdığımdan, ne yapmam gerektiğini tam olarak biliyorum. - troyal


Cevaplar:


Bunu yapmak için biraz daha verimli bir yol:

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

Mümkünse, "getData" öğesini tanımlayın, böylece oyuncuya ihtiyacınız yoktur.


42
2018-01-15 19:42



.EntrySet (), Harita üzerinden yineleme yapmanın en etkili yoludur ve bu nedenle, Harita'yı değiştirirseniz, bu durumda, Gerçek haritayı değiştirirsiniz. Ayrıca çok uygun. - Esko
Ben isterdim, ama getData () bu projenin yanı sıra diğerleri üzerinde de kullanılıyor, yani olduğu gibi bırakmak en iyisidir (bir Object'i döndürmek). - troyal
+1, Map <MyClass.Key, String> 'i döndürmek için getData () öğesini kesinlikle değiştirmeniz gerekir. Eski kodu bozmayacak. - Craig P. Motlin
+1 entrySet (), keySet () plus key lookups'tan daha iyidir. - cletus
harika bir örnek! Teşekkürler. entry.getKey () ve entry.getValue () öğesini kullanmam gerekiyordu. - ufk


Değişiklik:

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

için

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

Problem şu data.keySet() bir döndürür Collection<Object> veri sadece bir Map. Jenerik yaptıktan sonra, keySet() bir geri dönecek Collection<MyClass.Key>. Daha da iyisi ... entrySet(), bir olacak Collection<MyClass.Key, String>. Ekstra karma aramaları önler.


38
2018-01-15 19:32



Teşekkürler! Bunu neden düzelttiğini açıklayabilir misin? - troyal
Bunu açıkladığınızdan, Harita verisi, verileri Bilinmeyen türden bir Harita olarak bildirir, bu nedenle keySet (), Nesne döndürür. Değişiklik yapmak derleyiciye, anahtarların MyClass.Key değil Object olduğunu belirtir. - Paul Tomblin
Yalnızca veriyi Map data'ya atadığınızda, aslında onu <MapFrame, String> data olarak tanımlayarak Harita <Object, Object> 'e eşlemektesiniz, foreach döngüsünün anahtarın ne tür olduğuna dair bilgileri elde etmesine izin vermiş olursunuz. - Ryan Ahearn
-1 entrySet () bundan çok daha iyi. - cletus
@cletus, doğru, ama bu soruda bir sorun değildi. - Peter Štibraný


Bu basit örneği buldum java forumu. Onun sözdizimi Listenin foreach'una çok benzeraradığım şey buydu.

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

[DÜZENLE:] Test ettim ve mükemmel çalışıyor.


5
2018-04-19 21:40





Anahtar sınıfına ihtiyaç duymamak için bunun yerine entrySet'i kapabilirsiniz:

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
2018-01-15 19:39



KeysSet üzerinden yinelenen de anahtarların isimleri çıktı gerekiyor olsa bile, keySet üzerinden gitmeden daha verimli? - troyal
EntrySet daha etkilidir, çünkü her anahtarda bir arama yapmak zorunda kalmazsınız. - Michael Myers♦
@Blue - yol daha verimli BECAUSE hem anahtar hem de değer kullanıyorsunuz. - Paul Tomblin


Motlin'in cevabı doğru.

İki notum var ...

  1. Kullanma toString += ...ama kullan StringBuilder bunun yerine ve buna veri ekleyin.

  2. Martin'in önerdiği yayın, sizi kontrol edemediğiniz kontrolsüz bir uyarı verecek, çünkü gerçekten güvensiz.

Uyarı yapmadan başka bir yol (ve StringBuilder ile):

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

Bu çalışır, çünkü aradığınız toString yöntemi key Object sınıfında tanımlanmıştır, bu yüzden hiç bir döküm işlemine ihtiyacınız yoktur.

kullanma entrySet daha iyi bir yoldur, çünkü haritada başka bir göz atma ihtiyacı yoktur.


3
2018-01-15 19:38



@SuppressWarning ("işaretlenmemiş") ile uyarıdan kurtulabilirsiniz. - Ryan Ahearn
Bu sadece sorunları gizlemek, onları düzeltmek değil. @SuppressWarning ("unchecked"), BÜYÜK dikkatle kullanılmalıdır. - Peter Štibraný
Data.keSet () 'i yerel bir değişkende depolamanın mı yoksa foreach döngüsünün optimize edilmesinin daha iyi olup olmadığını merak ediyorum. - Alfred
@Alfred: data.keySet () öğesini kendi değişkeninize kaydetmenize gerek yoktur. (Nesne anahtarı: data.keySet ()) için şu koşullara eşdeğerdir: Yineleyici <Nesne> i = data.keySet (). yineleyici (); while (i.hasNext ()) {Nesne anahtarı = i.next (); ... döngü için geri kalanı buraya gider ...} Yani, data.keySet () sadece bir kez değerlendirilir. - Peter Štibraný
Cevabınız için teşekkürler :) - Alfred