Collection Map

I wanted to create a Map of Collections in Java, so I can do something like

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

I tried to do this with something like

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

but the compiler complains about the part <V>, and still there will be the problem of creating a proper new collection.

At the moment, I have created two classes: SetMap, which look like

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

and the ListMap looks pretty much the same except line 7 where I create a new ArrayList. Such duplication is small enough to be tolerated, but the question remains, is such "nested generics" possible in Java?

EDIT:

As erickson said , the solution is in <A, B extends Something<A>>, not just<B extends Something<A>>

so the code may look something like

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

and ListMap and SetMap provide only the appropriate collection

+3
5

map Map<K, Collection<V>>, idiom computeIfAbsent(...).add(...), :

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

, a Set:

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

, API Google - http://code.google.com/p/google-collections/.

, , , MultiMaps, .

+6

:

c = new Collection();

.

, :

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

Apache Commons collections also offer MultiMap, but this is pre-JDK 1-.5, so you will not have any protection against generics. You can wrap it in the Collections.checkedMap collection (Key.class, Value.class, collection) for runtime security. If you can use the Google Colelction API, it offers another MultiMap multiplexer with all the generics, calls and whistles.

+2
source

Use Google Guava if possible . The guys did a wonderful job there.

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

 }

You can use it as

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

Source: https://habr.com/ru/post/1698982/


All Articles