2013-02-18 45 views
14

Ho bisogno di scorrere il set di voci di una mappa da cui non conosco i suoi tipi parametrizzati.Iterating over a map entryset

Quando si esegue l'iterazione su tale entryset, perché questo non viene compilato?

public void myMethod(Map anyMap) { 
    for(Entry entry : anyMap.entrySet()) { 
     ... 
    } 
} 

ma questo compilazione:

public void myMethod(Map anyMap) { 
    Set<Entry> entries = anyMap.entrySet(); 
    for(Entry entry : entries) { 
     ... 
    } 
} 

e questo compila anche (non posso usare questo dato non so il tipo di mappa):

public void myMethod(Map<String, String> stringMap) { 
    for(Entry<String,String> entry : stringMap.entrySet()) { 
     ... 
    } 
} 
+0

controllare il nome della variabile – Renjith

+0

anche il secondo frammento di codice non deve compilare. I nomi delle variabili sono diversi. Sei sicuro che sia stato compilato? Pubblica il codice compilato quindi. Non scrivere da soli – SudoRahul

+0

thnaks @ Renjith, corretto il nome della variabile – Sergio

risposta

20

L'errore che si ottiene nel primo è:

Type mismatch: cannot convert from element type Object to Map.Entry 

Questo perché il compilatore converte il ciclo for-in:

for (Entry entry : anyMap.entrySet()) { 
} 

A:

for (Iterator i = anyMap.entrySet().iterator(); i.hasNext();) { 
    Entry e = i.next(); // not allowed 
} 

Il tuo secondo esempio funziona, ma solo attraverso barare! Stai facendo un cast non controllato per ottenere Setindietro in un Set<Entry>.

Set<Entry> entries = anyMap.entrySet(); // you get a compiler warning here 
for (Entry entry : entries) { 
} 

diventa:

Set<Entry> entries = anyMap.entrySet(); 
for (Iterator<Entry> i = entries.iterator(); i.hasNext();) { 
    Entry e = (Entry) i.next(); // allowed 
} 

Aggiornamento

Come accennato nei commenti, le informazioni sul tipo è perdersi in entrambi gli esempi: a causa delle regole di cancellazione di tipo grezzo del compilatore.

Per fornire la compatibilità all'indietro, TUTTI metodi delle istanze di tipo prime sono sostituiti dai loro cancellate controparti. Quindi, poiché il tuo Map è un tipo non elaborato, viene cancellato tutto. Compreso il suo metodo Set<Map.Entry<K, V>> entrySet();: la tua istanza di tipo non elaborata sarà costretta a utilizzare la versione cancellata: Set entrySet().

+0

+1 Questa è la risposta giusta. –

+0

ma poi perché nel primo caso 'anyMap.entrySet(). Iterator()' non sta restituendo un 'Iterator '?. Il valore restituito da 'entrySet()' è 'Set >', quindi un iteratore di questo set dovrebbe essere parametrizzato con 'Entry' anche se i tipi Key e Value non sono forniti, giusto? – Sergio

+0

@Sergio questo probabilmente perché l'Iteratore convertito non sta usando Generics. –

1

il primo codice lo snippet non verrà compilato perché la variabile map non esiste. Hai chiamato il parametro anyMap ma è tentato di accedervi come map, risolvere questo e il tuo codice verrà compilato a parte alcuni avvisi rawtypes

+1

No, non è giusto. –

+0

@BlankChisui. Supponendo che il nome della mappa fosse un refuso. Il problema sarà ancora quello che l'OP ha menzionato. Questo non è il problema del nome sbagliato. –

+0

sì il nome della mappa era un errore di battitura, già corretto, mi dispiace – Sergio

2

Nel primo esempio, map.entrySet() restituisce Set, quando si itera in ciclo si utilizza Iterator. Non ci sono informazioni sul tipo di contenuto dell'insieme, quindi Java usa Object as Object è il tipo di base e il compilatore ti dice che non può convertire Object in Entry.

Set<Map.Entry<K, V>> entrySet(); 

Quando si utilizza il tipo di mappa non elaborato, entrySet restituisce solo Set, senza informazioni sul tipo.

Nel secondo esempio, si converte manualmente Set in Set < Entry> (con avviso). Ora Java sa cosa c'è dentro. Quindi puoi iterare.

Nell'ultimo esempio si conosce il tipo di mappa, quindi entrySet restituisce il set digitato correttamente e si può iterare senza convenzioni di tipo.

4

È perché si utilizza il tipo di mappa non elaborato, quindi map.entrySet() ottiene un Set non parametrizzato che in cambio restituisce Object on iteration, non Entry.

Una soluzione semplice ma elegante è utilizzare Map <?,? >, che sarà comunque permetterà di passare qualsiasi mappa, ma dall'altra forze mano map.entrySet() per avere un valore di ritorno di Set <Entry>:

public void test(Map<?,?> map) {   
    for(Entry e : map.entrySet()){ 
     Object key = e.getKey(); 
     Object value = e.getValue(); 
    }  
} 
+0

ma se il valore restituito da 'entrySet()' è 'Set >, perché il set risultante non è parametrizzato con' Map.Entry 'anche se i tipi Key e Value non sono forniti? – Sergio

-1

Ho affrontato lo stesso problema. Sembra che il casting sia un problema. Ho provato il codice qui sotto e ha funzionato.

for(Object entry : hashMap.entrySet()) 
    { 
     System.out.println(((Entry<Object, Object>) entry).getKey() + " = " + ((Entry<Object, Object>) entry).getValue()); 

    } 
+0

Non utilizzare in primo luogo i tipi non elaborati e quindi puoi evitare un codice così sgradevole. – Tom

0

che stai ricevendo il rrror fase di compilazione, perché non si specifica il tipo di HashMap

Come

HashMap <(Integer,String> hm=new HashMap<(Integer,String>(); 

Se si specifica il tipo Integer e String, non è necessario ottenere l'errore del tempo di compilazione.

se non so che valore sta per aggiungere nella vostra HashMap quindi si utilizza

HashMap<(Object,Object> hm=new HashMap();