Карта коллекций - PullRequest
       15

Карта коллекций

4 голосов
/ 31 октября 2008

Я хотел сделать Карту Коллекций на Java, чтобы я мог сделать что-то вроде

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

Я пытался сделать что-то вроде

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

, но компилятор жалуется на часть <V>, и все равно будет проблема создания новой коллекции.

На данный момент я создал два класса: SetMap, которые выглядят так

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

и ListMap выглядит примерно так же, за исключением строки 7, где я создаю новый ArrayList. Такое дублирование достаточно мало, чтобы быть терпимым, но остается вопрос, возможен ли такой тип «вложенных обобщений» в Java?

EDIT:

Как сказал Эриксон , решение находится в <A, B extends Something<A>>, а не просто <B extends Something<A>>

поэтому код может выглядеть примерно так:

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

и ListMap и SetMap обеспечивают только надлежащую коллекцию

Ответы [ 5 ]

11 голосов
/ 31 октября 2008

Если map является Map<K, Collection<V>>, используйте идиому computeIfAbsent(...).add(...), , например:

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

Или, для Set:

map.computeIfAbsent(key, k -> new HashSet<>()).add(value);
6 голосов
/ 31 октября 2008

Если это вариант, вы можете просто использовать API Google Collections - http://code.google.com/p/google-collections/.

Даже если вы не можете использовать его, возможно, взгляните на то, как они реализовали свои MultiMaps, поможет вам в вашей реализации.

2 голосов
/ 02 ноября 2008

Если возможно, используйте Google Guava . Ребята проделали там замечательную работу.

Вот еще одно решение.

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

 }

Вы можете использовать его как

MultiMap<String, Integer> data = MultiMap.newArrayListMultiMap();
data.put("first", 1);
data.put("first", 2);
data.put("first", 3);
2 голосов
/ 01 ноября 2008

Apache Commons Collections также предлагает MultiMap, но это до JDK 1 -5, так что у вас там не будет безопасности дженериков. Вы можете поместить его в коллекцию Collections.checkedMap (Key.class, Value.class, collection) для обеспечения безопасности во время выполнения. Если вы можете использовать Google Colelction API, он предлагает еще более привлекательную MultiMap со всеми шаблонами, прибамбасами и свистками.

2 голосов
/ 31 октября 2008

Проблема с вашим кодом:

Коллекция c = новая коллекция ();

Невозможно создать экземпляр.

Я думаю, что следующий фрагмент кода решит вашу проблему:

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