 |
Mapping with HashMap
Using HashMap, autoboxing and the for-each loop.
The java.util.HashMap is part of the Sun Java Collections Framework and an
implementation of the interface Map. It is equivalent to the
Hashtable, but not synchronised and permits null for values or a key.
|
The purpose of the Map classes is to map key objects to value objects. This
might be id keys to business logic objects, or any other one-to-one, or in fact
many-to-one mapping. That is, a key can only appear once, and can only map to
one value, however nothing prevents the same value being mapped from different
keys.
HashMap, and most of the other Java Collections Framework, use the equals() and
hashCode() methods to define unique objects or keys. This means that
a.equals(b) will be the same key if this expressions returns true. For example,
(new Integer(1)).equals(1), will return true, even if they don't refer to the
same constructed instance of the Integer class. The String class, which is also
immutable, works in the same way.
The following code exemplifies these concepts:
EqualsTest.java
|
|
Now for the actual HashMap; usage normally constitutes defining keys, somehow
creating objects that need to be mapped and at a later stage looking up those
objects based on their keys.
int a = 1;
int b = 2;
Map map = new HashMap();
Here we have defined to keys, in fact as primitive int types, and construct
the map object. Note how the interface and not the actual class name is used.
This way we can easily change Map implementation without changing much of
our code.
map.put(a, "first value");
map.put(b, "second value");
Then we insert or put the key/value pairs. Note how auto-boxing is used to
create the key objects. Of course explicit construction of the Integer wrapper
class will do exactly the same.
System.out.println("First: "+map.get(a));
System.out.println("Second: "+map.get(2));
And finally we retrieve the stored values used the keys. Note how both the
original int a and the number 2 give the correct keys.
HashMapTest.java
|
|
And then, in the final HashMap example for now, we'll implement a small
application which counts the number of unique words in a String.
The program will read all the arguments from the command-line and treat each
for as a separate token, which will be used as a key in the HashMap. The
HashMap value of each key will be the number of occurrences of that word, or
token. The code segment below shows how this can be done, using a the new
for-each loop and autoboxing to put and get the count values.
for(String word : words) {
if(map.containsKey(word)) {
int count = (Integer)map.get(word);
map.put(word, count+1);
}
else {
map.put(word, 1);
}
}
The reading of this Map counting String keys and Integer values is quite
simple, as the code below shows.
for(Object word : map.keySet()) {
int count = (Integer)map.get(word);
System.out.println(""+word+": "+count);
}
Uniq.java
Finally, note how easy it is to change the implementation of the Map interface.
The HashMap is constructed in one single place in the code, and by swapping it
for a java.util.TreeMap, we may change the output of the program to an ordered list.
private Map countWords(String words[]) {
Map map = new TreeMap();
(...)
}
|
|
Note that the examples used in the above section use some of the new Java 5.0
(JDK 1.5) features, however miss one important one; generics. The examples on
this page are particularly good ones for the usage of generics, since we have
strictly defined types contained in the HashMap.
For examples on how to use generics in these small programs, stay tune for
more from this site.
|
|
|
 |