[an error occurred while processing this directive]
Domain for sale!
Start Search Contents Index Links About

Mapping with HashMap

Using HashMap, autoboxing and the for-each loop.

2005 - Week 39 - Havard Rast Blok

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.



site: Håvard Rast Blok
mail:
updated: 16 July 2010