2015-08-26 4 views
0

Comment puis-je créer vivify une clé avec des génériques? Ce code ne compile même pas:Fonction autovivify générique pour les cartes

/* populate the map with a new value if the key is not in the map */ 
private <K,V> boolean autoVivify(Map<K,V> map, K key) 
{ 
    if (! map.containsKey(key)) 
    { 
    map.put(key, new V()); 
    return false; 
    } 
    return true; 
} 
+0

Cela semble compiler (non testé): '(V) (map.getClass(). GetTypeParameters() [1] .getClass()). NewInstance()' – perreal

Répondre

1

Vous devrez indiquer à la méthode comment créer la valeur.

interface Producer<T> { 

    T make(); 
} 

private <K, V> boolean autoVivify(Map<K, V> map, K key, Producer<V> maker) { 
    if (!map.containsKey(key)) { 
     map.put(key, maker.make()); 
     return false; 
    } 
    return true; 
} 

Vous pouvez également - utiliser null. HashMap peut contenir null bien que puisse avoir des difficultés.

private <K, V> boolean autoVivify(Map<K, V> map, K key) { 
    if (!map.containsKey(key)) { 
     map.put(key, null); 
     return false; 
    } 
    return true; 
} 
+0

En fait, TreeMap peut contenir null s'il est créé avec un comparateur null-friendly. –

+0

@TagirValeev - Même pour la valeur? Des choses étranges vont sûrement arriver parce que plusieurs méthodes de 'TreeMap' sont définies pour retourner' null' si la clé n'est pas trouvée. – OldCurmudgeon

+0

Ah, désolé. Pour les valeurs, vous n'avez même pas besoin du comparateur. TreeMap supporte parfaitement les valeurs nulles. –

1

Si V ont un constructeur sans argument, vous pouvez utiliser la réflexion pour créer une instance

private <K, V> boolean autoVivify(Map<K, V> map, K key, Class<V> clazz) throws Exception { 
    if (!map.containsKey(key)) { 
     map.put(key, clazz.getConstructor().newInstance()); 
     return false; 
    } 
    return true; 
} 

Map<Integer, String> map = new HashMap<>(); 
autoVivify(map, 3, String.class); 
4

En Java-8, il est raisonnable de fournir un Supplier et utiliser computeIfAbsent:

private <K,V> boolean autoVivify(Map<K,V> map, K key, Supplier<V> supplier) { 
    boolean[] result = {true}; 
    map.computeIfAbsent(key, k -> { 
     result[0] = false; 
     return supplier.get(); 
    }); 
    return result[0]; 
} 

Exemple d'utilisation:

Map<String, List<String>> map = new HashMap<>(); 
autoVivify(map, "str", ArrayList::new); 

Notez que contrairement aux solutions containsKey/put utilisant computeIfAbsent est sûr pour les cartes simultanées: aucune condition de concurrence ne se produira.