Something to keep in mind is that the value will initially be null, so the first time you use a key, you'll have to initialize it:
Map<String,Set<Integer>> map;
To add a number to the key, you must do this:
String key = "apple"; // for example
Set<Integer> set = map.get(key);
if (set == null) {
set = new HashSet<Integer>();
map.put(key, set);
}
set.add(5);
Unfortunately, everywhere you interact with the set, you must null check. For example, if you want to check if a certain key had a certain number mapped to it, you couldn't safely do this:
if (map.get(key).contains(number)) // not safe
because the call to get()
may return null
(if there's no entry for the key) and you'd get a NullPointerException
.
There is a way to make your map very convenient to use by internalising the null check inside the map, so that a call to get()
will always return a non-null set; create an anonymous class that overrides get()
accordingly:
Map<String,Set<Integer>> map = new HashMap<String,Set<Integer>> () {
@Override
public Set<Integer> get(Object key) {
Set<Integer> set = super.get(key);
if (set == null) {
set = new HashSet<Integer>();
put(key, set);
}
return set;
}
}
With this in place, your main code becomes a lot simpler and clearer. To add:
map.get(key).add(number);
To check:
if (map.get(key).contains(number)) // now safe
The null checking code is no longer necessary.
——
Java 8 update:
To deal with the null entry problem when adding to the set:
map.computeIfAbsent( key, k -> new HashSet<>() ).add(number);
and for null safe checking:
if ( map.getOrDefault(key, Collections.emptySet() ).contains(number))