1. A set of key-value pairs.

A set of key-value pairs

In Java, another interesting collection (broadly speaking) is Map. Sometimes this data structure is also called a dictionary.

It is similar to the Set collection, but it stores a set of "pairs" of elements rather than a set of elements, Each pair in a Map consists of two elements: a "key" and a "value".

Let's say you want your program to store employee names and their salaries, or your coworkers names and their ages. Then you would need a table like this:

Name Age
Elon 21
Jeff 22
Bill 48
Warren ?

Each row contains a couple of values. We will refer to the name as the pair's key, and the age as the pair's value.

The whole set of these pairs is our map (Map).

A pair's key can be anything, but for some types of maps the key cannot be null. Keys must be unique: one map cannot contain two identical keys.


2. HashMap class

The HashMap class is the most popular kind of Map collection. On the one hand, it is very similar to HashSet and has all its methods. On the other hand, it is like a list (ArrayList) that can use words (or anything else) as its indices.

You can create a HashMap using a statement like this:

HashMap<KeyType, ValueType> name = new HashMap<KeyType, ValueType>();

Where KeyType is the type of the keys in the stored pairs, and ValueType is the type of the values in the pairs stored in the HashMap collection.

The HashMap class has methods like this:

Method Description
void put(KeyType key, ValueType value)
Adds the (key, value) pair to the collection
ValueType get(KeyType key)
Returns the value associated with a key.
boolean containsKey(KeyType key)
Checks whether a key exists in the collection
boolean containsValue(ValueType value)
Checks for the existence of a value in the collection
ValueType remove(KeyType key)
Removes an element from the collection
void clear()
Clears the collection, removing all the elements
int size()
Returns the number of key-value pairs in the collection
Set<KeyType> keySet()
Returns the set of keys in the collection
Collection<ValueType> values()
Returns a set containing the elements of the collection
Set<Map.Entry<KeyType, ValueType>> entrySet()
Returns a set (Set) of all pairs (Map.Entry) in the collection.

Adding elements to a HashMap

Elements are added to a map as pairs using the put() method. The key is passed as the first argument, and the value is passed as the second.

HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("Elon", 21);
map.put("Jeff", 22);
map.put("Bill", 48);
map.put("Warren", null);

When adding a key-value pair, if the key already exists in the collection, then the old value is replaced by the new value.

This behavior makes a HashMap like an array or a list whose indices are words (String) instead of numbers.

Important:

Almost any type can be the KeyType or ValueType. There are some small additional requirements for the KeyType, and you will learn about them when you study collections in greater detail in the Java Collections quest.



3. Subsets of a HashMap: the set of keys

Let's say we just want to display all the entries in a HashMap on the screen. How do we do this? To do this, we need to know how to go through all the entries in the HashMap. This can be done in several ways.

The easiest way is to loop over the keys

HashMap entries are not numbered sequentially, so a loop with a counter won't work here. But we can get a set of keys using the keySet() method, and you already know how to iterate over a set:

Code Description
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("Elon", 21);
map.put("Jeff", 22);
map.put("Bill", 48);
map.put("Warren", null);

for (String key: map.keySet())
{
   Integer value = map.get(key);
   System.out.println(key + " --> " + value);
}






Loop over the keys of the map

Get the value associated with the key

The keySet() method returns a set of keys. You can use this set in two ways:

Compact notation Long notation
for (String key: map.keySet())
{
   Integer value = map.get(key);
   System.out.println(key + " --> " + value);
}
Set<String> keys = map.keySet();

for (String key: keys)
{
   Integer value = map.get(key);
   System.out.println(key + " --> " + value);
}


4. Looping over key-value pairs

There is also a more complicated way: you can transform a Map into a set of key-value pairs, and then loop over the elements of the set, as we have already learned.

The HashMap collection has a helper class that stores a key-value pair. It looks approximately like this:

class Entry<KeyType, ValueType>
{
   private KeyType key;
   private ValueType value;

   public KeyType getKey()
   {
      return this.key;
   }

   public ValueType getValue()
   {
      return this.value;
   }
}

The result of calling the entrySet() method on a HashMap<KeyType, ValueType> object will be a Set<Entry<KeyType, ValueType>>:

Set<Entry<KeyType, ValueType>> name = map.entrySet();

Here we have the generic Set class with a type parameter, which in turn is a generic type (Entry) with two type parameters.

It is very easy for a beginner to get confused about this. But once you figure it out, you can write code like:

HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("Elon", 21);
map.put("Jeff", 22);
map.put("Bill", 48);
map.put("Warren", null);

Set<Map.Entry<String, Integer>> entries = map.entrySet();
for(Map.Entry<String, Integer> pair: entries)
{
   String key = pair.getKey();
   Integer value = pair.getValue();
   System.out.println(key + " --> " + value);
}

That said, this code can be simplified a little:

First, you can skip creating a separate variable for entries and instead call the entrySet() method directly inside the for loop:

for(Map.Entry<String, Integer> pair: map.entrySet())
{
   String key = pair.getKey();
   Integer value = pair.getValue();
   System.out.println(key + " --> " + value);
}

Second, you can use the recently introduced var operator to automatically infer the type of the key-value pair:

for(var pair: map.entrySet())
{
   String key = pair.getKey();
   Integer value = pair.getValue();
   System.out.println(key + " --> " + value);
}

Not bad, eh?



5. Comparison of ArrayList and HashMap

A HashMap strongly resembles an ArrayList that allows strings (or other types) to be used as indexes (the keys).

If you use Integer for the keys in a HashMap, then it becomes even more similar to an ArrayList. Let's compare:

Code with ArrayList<String> Code with HashMap<Integer, String>
ArrayList<String> list = new ArrayList<String>();

list.add("Greetings");
list.add("Hello");

String s = list.get(0);
list.set(0, s + "!");

for (String item: list)
{
   System.out.println(item);
}
HashMap<Integer, String> map = new HashMap<Integer, String>();

map.put(0, "Greetings");
map.put(1, "Hello");

String s = map.get(0);
map.put(0, s + "!");

for (String item: map.values())
{
   System.out.println(item);
}