The Map Interface

In Java, maps are defined by the interface java.util.Map, which includes put and get methods as well as other general methods for working with maps. The map interface, Map<K,V>, is parameterized by two types. The first type parameter, K, specifies the type of objects that are possible keys in the map; the second type parameter, V, specifies the type of objects that are possible values in the map. For example, a map of type Map<Date,JButton> would associate values of type JButton to keys of type Date. For a map of type Map<String,String>, both the keys and the values are of type String.

Suppose that map is a variable of type Map<K,V> for some specific types K and V. Then the following are some of the methods that are defined for map:

  • map.get(key) – returns the object of type V that is associated by the map to the key. key can be any object; it does not have to be of type K. If the map does not associate any value with key, then the return value is null. Note that it’s also possible for the return value to be null when the map explicitly associates the value null with the key. Referring to “map.get(key)” is similar to referring to “A[key]” for an array A. (But note that there is nothing like an IndexOutOfBoundsException for maps.)
  • map.put(key,value) – Associates the specified value with the specified key, where key must be of type K and value must be of type V. If the map already associated some other value with the key, then the new value replaces the old one. This is similar to the command “A[key] = value” for an array.
  • map.putAll(map2) – if map2 is another map of type Map<K,V>, this copies all the associations from map2 into map.
  • map.remove(key) – if map associates a value to the specified key, that association is removed from the map. key can be any object; it does not have to be of type K.
  • map.containsKey(key) – returns a boolean value that is true if the map associates some value to the specified key. key can be any object; it does not have to be of type K.
  • map.containsValue(value) – returns a boolean value that is true if the map associates the specified value to some key. value can be any object; it does not have to be of type V.
  • map.size() – returns an int that gives the number of key/value associations in the map.
  • map.isEmpty() – returns a boolean value that is true if the map is empty, that is if it contains no associations.
  • map.clear() – removes all associations from the map, leaving it empty.

The put and get methods are certainly the most commonly used of the methods in the Map interface. In many applications, these are the only methods that are needed, and in such cases a map is really no more difficult to use than a standard array.

Java includes two classes that implement the interface Map<K,V>TreeMap<K,V> and HashMap<K,V>. In a TreeMap, the key/value associations are stored in a sorted tree, in which they are sorted according to their keys. For this to work, it must be possible to compare the keys to one another. This means either that the keys must implement the interface Comparable<K>, or that a Comparator must be provided for comparing keys. (The Comparator can be provided as a parameter to the TreeMap constructor.) Note that in a TreeMap, as in a TreeSet, the compareTo() method is used to decide whether two keys are to be considered the same. This can have undesirable consequences if the compareTo() method does not agree with the usual notion of equality, and you should keep this in mind when using TreeMaps.

HashMap does not store associations in any particular order, so the keys that can be used in a HashMap do not have to be comparable. However, the key class should have reasonable definitions for the equals() method and for a hashCode() method that is discussed later. Most of Java’s standard classes define these methods correctly. Most operations are a little faster on HashMaps than they are on TreeMaps. In general, you should use a HashMap unless you have some particular need for the ordering property of a TreeMap. In particular, if you are only using the put and get operations, you can safely use a HashMap.

Let’s look at an example where maps would be useful. Consider a simple PhoneDirectory class that associates phone numbers with names. This class defines operations addEntry(name,number) and getNumber(name), where both name and number are given as Strings. In fact, the phone directory is acting just like a map, with the addEntry method playing the role of the put operation and getNumber playing the role of get. In a real programming application, there would be no need to define a new class; we could simply use a map of type Map<String,String>. A directory would be defined as:

Map<String,String> directory = new Map<String,String>();

and then directory.put(name,number) would record a phone number in the directory and directory.get(name) would retrieve the phone number associated with a given name.

Next: Views, Subsets and Submaps