Reputation: 3123
I'm trying to write a generic function that will add an element to a Map
of Collection
s. This works for a Map
of List
s:
public static <TKey, TVal> void addToMapOfLists(Map<TKey, List<TVal>> map, TKey key, TVal val) {
List<TVal> list = map.get(key);
if (list == null) {
list = new ArrayList<>();
list.add(val);
map.put(key, list);
} else
list.add(val);
}
I want to make this function work on Map<TKey, Set<TVal>>
as well as on Map<TKey, List<TVal>>
. I expect this should be possible because both implement Collection
that has the add(TVal)
member that I call.
My problem is that when I try change the parameter Map<TKey, List<TVal>> map
to Map<TKey, ? extends Collection<TVal>> map
- I need to somehow replace new ArrayList<>();
with a call to the constructor of the implementer of Collection
.
Upvotes: 2
Views: 2455
Reputation: 394126
You will have to pass an additional parameter to your method - a Supplier
of Collection
instances.
Here's one possible implementation :
public static <TKey, TVal, TCol extends Collection<TVal>> void addToMapOfCollections(Map<TKey, Collection<TVal>> map, TKey key, TVal val, Supplier<TCol> supplier)
{
Collection<TVal> col = map.get(key);
if (col == null) {
col = supplier.get ();
col.add(val);
map.put(key, col);
} else {
col.add(val);
}
}
Here's another option :
public static <TKey, TVal> void addToMapOfCollections(Map<TKey, Collection<TVal>> map, TKey key, TVal val, Supplier<Collection<TVal>> supplier)
{
Collection<TVal> col = map.get(key);
if (col == null) {
col = supplier.get ();
col.add(val);
map.put(key, col);
} else {
col.add(val);
}
}
And with less code (as suggested by Gerald) :
public static <TKey, TVal> void addToMapOfCollections(Map<TKey, Collection<TVal>> map, TKey key, TVal val, Supplier<Collection<TVal>> supplier)
{
map.putIfAbsent(key, supplier.get());
map.get(key).add(val);
}
I tested the second variant :
Map<String,Collection<Integer>> map = new HashMap<String, Collection<Integer>>();
addToMapOfCollections(map,"String1",5,HashSet::new);
addToMapOfCollections(map,"String2",67,ArrayList::new);
addToMapOfCollections(map,"String2",68,ArrayList::new);
System.out.println (map);
for (Collection<Integer> col : map.values ()) {
System.out.println (col.getClass () + " : " + col);
}
Output :
{String2=[67, 68], String1=[5]}
class java.util.ArrayList : [67, 68]
class java.util.HashSet : [5]
Upvotes: 7