2008-10-31 12 views
3

Je voulais faire Carte des collections en Java, donc je peux faire quelque chose commeCarte des collections

public void add(K key, V value) { 
    if (containsKey(key)) { 
     get(key).add(value); 
    } else { 
     Collection c = new Collection(); 
     c.add(value); 
     put(key, value); 
    } 
} 

J'ai essayé de le faire avec quelque chose comme

public class CollectionMap<K, C extends Collection<V>> extends HashMap<K, C> 

mais compilateur se plaint la partie <V>, et il y aurait encore un problème de faire une nouvelle collection appropriée.

En ce moment, je l'ai fait deux classes: setMap qui ressemblent à ceci

1: public class SetMap<K, V> extends HashMap<K, Set<V>> { 
2: 
3: public void add(K key, V value) { 
4:  if (containsKey(key)) { 
5:   get(key).add(value); 
6:  } else { 
7:   Set<V> list = new HashSet<V>(); 
8:   list.add(value); 
9:   put(key, list); 
10:  } 
11: } 
12: 
13: } 

et ListeCarte regarde à peu près le même, sauf la ligne 7, où je fais nouvelle ArrayList. Ce genre de duplication est assez petit pour être tolérable, mais la question reste de savoir si ce genre de "génériques imbriqués" est possible en Java?

EDIT:

Comme erickson said, solution est <A, B extends Something<A>> plutôt que <B extends Something<A>>

si le code peut ressembler à quelque chose comme

public abstract class CollelctionMap<K, V, C extends Collection<V>> extends HashMap<K, C> { 

    protected abstract C newCollection(); 

    public void add(K key, V value) { 
     if (containsKey(key)) { 
      get(key).add(value); 
     } else { 
      C c = newCollection(); 
      c.add(value); 
      put(key, c); 
     } 
    } 
} 

et ListeCarte et setMap fournir la seule collection appropriée

Répondre

9

Si map est un Map<K, Collection<V>>, utilisez l'idiome computeIfAbsent(...).add(...), comme ceci:

map.computeIfAbsent(key, k -> new ArrayList<>()).add(value); 

Ou, pour un Set:

map.computeIfAbsent(key, k -> new HashSet<>()).add(value); 
6

Si c'est une option, vous pouvez simplement utiliser l'API Google Collections - http://code.google.com/p/google-collections/.

Même si vous ne pouvez pas l'utiliser, peut-être que vous devriez voir comment ils ont implémenté leurs MultiMaps pour vous aider dans votre implémentation.

2

Il y a un problème avec votre code:

Collection c = new Collection();

Impossible d'être instancié.

Je pense que le prochain morceau de code résoudra votre problème:

public class CollectionMap<K, V> extends HashMap<K, Collection<V>> { 


    ... 
    ... 
    ... 


    public void add(K key, V value) { 
     if (containsKey(key)) { 
      get(key).add(value); 
     } else { 
      Collection<V> c = new ArrayList<V>(); 
      c.add(value); 
      super.put(key, c); 
     } 
    } 
} 
+0

oui, je l'ai mentionné que, il est juste là une idée à illustrer – Slartibartfast

2

Apache Commons Collections offre également un Multimap, mais il est pré-jdk de 1 à 0,5, de sorte que vous aurez il pas la sécurité des médicaments génériques . Vous pouvez l'intégrer dans Collections.checkedMap (Key.class, Value.class, collection) pour la sécurité d'exécution. Si vous pouvez utiliser l'API Colelction de Google, elle offre un MultiMap encore plus luisant avec tous les génériques, cloches et sifflets.

2

Si possible, utilisez le Guava de Google. Les gars ont fait un travail merveilleux là-bas.

Voici une autre solution.

abstract class MultiMap<K, V> { 

    private Map<K, Collection<V>> entries = new LinkedHashMap<K, Collection<V>>(); 

    public void put(K key, V value) { 
     Collection<V> values = entries.get(key); 
     if (values == null) { 
      entries.put(key, values = newValueCollection()); 
     } 
     values.add(value); 
    } 

    // other methods 
    // .. 

    abstract Collection<V> newValueCollection(); 



    // Helper methods to create different flavors of MultiMaps 

    public static <K, V> MultiMap<K, V> newArrayListMultiMap() { 
     return new MultiMap<K, V>() { 
      Collection<V> newValueCollection() { 
       return new ArrayList<V>(); 
      } 
     }; 
    } 

    public static <K, V> MultiMap<K, V> newHashSetMultiMap() { 
     return new MultiMap<K, V>() { 
      Collection<V> newValueCollection() { 
       return new HashSet<V>(); 
      } 
     }; 
     } 

} 

Vous pouvez l'utiliser comme

MultiMap<String, Integer> data = MultiMap.newArrayListMultiMap(); 
data.put("first", 1); 
data.put("first", 2); 
data.put("first", 3);