2015-01-17 11 views
6

Ho il seguente:Come convertire Java 8 map.remove in Java 1.6?

 fruitMap.remove(fruitId, fruitProperties); 

Il fruitMap è:

private Map<FruitId, FruitProperties> fruitMap = new HashMap<FruitId, FruitProperties>(); 

Quando si tenta di costruire il mio codice ho un:

ERROR 
The method remove(Object) in the type Map<MyImplementation.FruitId, FruitProperties> 
is not applicable for the arguments (Map<MyImplementation.FruitId, FruitProperties>) 

Qual è il problema?

Si noti che questa chiamata è all'interno di un metodo "removeFruit()" all'interno della mia classe "FruitImplementation".

+0

Come viene definito 'fruitId'? – Todd

risposta

2

Il metodo remove(key, value) rimuove la voce per key se è attualmente associata a value. Il metodo è stato aggiunto in Java 1.8. Il Javadoc per l'interfaccia Map cita la seguente implementazione di default:

if (map.containsKey(key) && Objects.equals(map.get(key), value)) { 
    map.put(key, newValue); 
    return true; 
} else 
    return false; 

Poiché la classe Objects è stato aggiunto solo in Java 1.7, per Java 1.6 dovete scrivere l'uguaglianza mettervi alla prova. Quindi, se non è necessario il valore di ritorno del metodo, è possibile sostituire con map.remove(key, value):

if (map.containsKey(key) { 
    Object storedValue = map.get(key); 
    if (storedValue == null ? value == null : storedValue.equals(value)) { 
     map.remove(key); 
    } 
} 

Si noti che questo non è thread-safe. Se accedi alla mappa da più thread, dovrai aggiungere un blocco sincronizzato.

2

Dovrete verificare il valore da soli:

if(fruitProperties.equals(fruitMap.get(fruitId)) { 
    fruitMap.remove(fruitId); 
} 

nota, mia implementazione qui assume che si sta testando un fruitProperties oggetto non nullo.

7

Da the Javadocs:

Il predefinito attuazione è equivalente a, per questa mappa:

if (map.containsKey(key) && Objects.equals(map.get(key), value)) { 
    map.remove(key); 
    return true; 
} else 
    return false; 

L'implementazione predefinita non fornisce alcuna garanzia riguardo sincronizzazione o atomicità proprietà di questo metodo. Qualsiasi implementazione che fornisca garanzie di atomicità deve sovrascrivere questo metodo e documentarne le proprietà di concorrenza.

Quindi è possibile utilizzare quell'implementazione predefinita. Mettilo in un metodo di supporto statico, forse.

Ma se questo dovrebbe essere thread-safe, potrebbe essere necessario aggiungere un po 'di codice di sincronizzazione (o considerare l'utilizzo di una ConcurrentMap, che tra l'altro ha già il metodo remove da Java 5).

+2

Java 6 non ha la classe 'Objects'. –

+3

ah .. Lo lascerò come esercizio al lettore. :-) – Thilo

+0

Penso che debba essere sincronizzato? Come fai a non avere una classe di oggetti? Non sono sicuro che sia necessario o no, voglio preservare quello stile di codice senza rompere nulla. – Rolando

1

Hai bisogno di fare i seguenti assumendo i valori non può essere null

if (fruitProperties.equals(fruitMap.get(fruitId)) 
    fruitMap.remove(fruitId); 

Nota: per questo di essere thread-safe si avrebbe bisogno di avvolgere questo in un blocco synchronized.

1

Ecco la soluzione completa, la gestione di synchronization e casi specifici come i valori null.

synchronized (fruitMap) 
{ 
    if ((fruitMap.containsKey(fruitId) // The key is present 
    && (
      (fruitProperties == null && fruitMap.get(fruitId) == null) // fruitProperties is null, so is the stored value 
     || (fruitProperties != null && fruitProperties.equals(fruitMap.get(fruitId))) 
     ) 
    ) 
    { 
     fruitMap.remove(fruitId); 
    } 
} 

Funziona in Java 6, si tratta di un equivalente a:

fruitMap.remove(fruitId, fruitProperties); 
1

Objects.equals ha un'implementazione in questo modo:

public static boolean equals(Object a, Object b) { 
    return (a == b) || (a != null && a.equals(b)); 
} 

Pertanto, l'implementazione predefinita di rimuovere:

if (map.containsKey(key) && Objects.equals(map.get(key), value)) { 
    map.remove(key); 
    return true; 
} else 
    return false; 

può essere scritto in Java 6 come:

if (map.containsKey(key) && ((map.get(key) == value) || (map.get(key) != null && map.get(key).equals(value)))) { 
    map.remove(key); 
    return true; 
} else 
    return false; 
1

Come per la Java Doc, rimuovere (Object key, Object value)

Rimuove la voce per la chiave specificata solo se è attualmente mappata al valore specificato.

Se i equals() viene correttamente definito, si può fare qualcosa di simile

FruitProperties valueFromMap = map.get(key); 
if(valueFromMap != null){ 
    if(valueFromMap == originalValue || valueFromMap.equals(originalValue)){ 
    map.remove(key); 
    } 
} 

Ora che si sta utilizzando semplici HashMap, presumo che ti prende cura di thread-sicurezza da parte o sincronizzandolo o modificandolo in ConcurrentHashMap :)