Generic Map in Java
Jakob Jenkov |
Java's Map
interface (java.util.Map
) can be generified. In other words,
you can set the specific type of both the keys and values in a generic Map
instance.
Here is an example:
Map<Integer, String> set = new HashMap<Integer, String>;
This Map
can now only accept Integer
instances
as keys, and String
instances as values.
The generic type checks only exists at compile time. At runtime it is possible to tweak your code so that other instances can be inserted. This is a bad idea, though.
Accessing a Generic Map
Adding and getting elements to a generic Map
is done using the put()
and get()
methods, just like you have always done:
Map<Integer, String> map = new HashMap<Integer, String>; Integer key1 = new Integer(123); String value1 = "value 1"; map.put(key1, value1); String value1_1 = map.get(key1);
So what is the big difference? Well, if you try to add a key, value pair that is
not a Integer, String
pair instance, to the Map
in the example above,
the compiler will complain. That's a pretty nice extra type check to have.
Also notice how it is not necessary to cast the String
instance returned
by the get()
method. The compiler knows that this Map
has
String
values, so casting is not necessary.
You can also use the new auto boxing features of Java 5 to make it easier to specify the
Integer
values, like this:
Map<Integer, String> map = new HashMap<Integer, String>; Integer key1 = 123; String value1 = "value 1"; map.put(key1, value1); //or map.put(123, value1); String value1_1 = map.get(123);
Iterating a Generic Map
A Map
has two collections you can iterate. The key Set
and the value Set
. Most often you iterate the key Set
and access the values for each key via the Map.get()
method.
Here are two examples:
Map<Integer, String> map = new HashMap<Integer, String>; //... add key, value pairs to the Map // iterate keys. Iterator<Integer> keyIterator = map.keySet().iterator(); while(keyIterator.hasNext()){ Integer aKey = keyIterator.next(); String aValue = map.get(aKey); } Iterator<String> valueIterator = map.values().iterator(); while(valueIterator.hasNext()){ String aString = valueIterator.next(); }
Notice how it is not necessary to cast the object returned from the
iterator.next()
next call. Because the Map
is generified (has a type), the compiler knows that it contains
Integer
instances for keys, and String
instances for values. Therefore it is not necessary to cast the objects obtained from
the Map
, even if it comes from one of its Iterator
's.
You can also use the new for-loop, like this:
Map<Integer, String> map = new HashMap<Integer, String>; //... add key, value pairs to the Map for(Integer aKey : map.keySet()) { String aValue = map.get(aKey); System.out.println("" + aKey + ":" + aValue); } for(String aValue : map.values()) { System.out.println(aValue); }
Notice how an Integer
and a String
variable is declared inside the parantheses of
each for-loop. For each iteration (each element in the Map
's key set or value collection) this
variable contains the current element (current Integer or String).
Tweet | |
Jakob Jenkov |