Overview of This Lesson

This is just a quick review of Lists and Maps.

Review of Lists and Maps

Recall that ArrayList is a type of List. Lists contain objects and can't contain primitive values. For example, a List can contain an Integer, but not an int. Also, lists organize their elements by a 0-based index.

Recall that when we work with Collections, or any other class with a generic type, we always replace that generic type with a concrete type. This ensures that:

  1. Only instances of that type, and its children, are permitted. For example, this is not permitted:
    ArrayList<Cat> cats = new ArrayList<Cat>();
    cats.add(new Scanner(System.in));
  2. There is a minimal amount of code required to work with objects in the list. For example, before we had Generic Syntax, we would have:
    ArrayList cats = new ArrayList();
    cats.add(new Cat());
    cats.add(new Cat("Arti"));
    // print a cat
    System.out.println( ((Cat)cats.get(0)).catInfo() );
    // print all cats
    for (Object ob : cats) {
        Cat c = (Cat)ob;
        System.out.println(c.catInfo());
    }
    Without generics, all objects put into a list are stored in that list as Object. So a programmer must always add code to cast those objects back into whatever they were supposed to be to begin with. When using a concrete type, the List knows it only contains cats, so casting isn't necessary:
    ArrayList<Cat> cats = new ArrayList<Cat>();
    cats.add(new Cat());
    cats.add(new Cat("Arti"));
    // print a cat
    System.out.println(cats.get(0).catInfo() );
    // print all cats
    for (Cat c : cats) {
    System.out.println(c.catInfo());
    }

Maps

Maps are similar to Lists in that they contain a list of objects, however where a List's elements are indexed with integer indexes starting at 0, a Map's indexes can be any unique object: it can be an Integer object, String object, or any other object. A Map's elements are key-value pairs, where the key is the unique object that acts as the index, and the value is the object or value associated with each index.

a list of indexed generic values beside a map of generic key-value pairs
A List's elements are organized by index.
A Map contains key-value pairs.

Maps also use generic syntax, so Map<K, V> is used to identify a Map with a generic type K for the key and V for the value.

In fact, a Map is actually a collection of Map.Entry<K, V> objects. Entry is a nested class inside the Map class, which is why we refer to it as Map.Entry. Map.Entry<K, V> models a single key-value pair. This is why we call map elements "entries" rather an "elements" or "items".

a box containing a key-box and a value-box; a map containing several of those boxes
A Map is a collection of Map.Entry objects.
A Map.Entry object consists of a key-value pair.

A HashMap is a special kind of Map that's very efficient when it comes to adding, removing, and searching for map elements.

When you create a HashMap, you must specify a concrete type for both the Key and the Value:

HashMap<Integer, Cat> cats = new HashMap<Integer, Cat>();

In this example, I'm using an Integer object (a boxed int) as the key and a Cat object as the value.

HashMap<String, Container> containers = new HashMap<String, Container>();

Here I'm using a String object as the key and a Container object as the value.

HashMap<Container, Inventory> shipments = new HashMap<Container, Inventory>();

Here I'm using a Container object as the key and an Inventory object as the value.

Remember that whatever you decide to use for your key, that's the entry's index, so that key must be unique. You cannot use the same key more than once in a Map.

To add elements to a map, we use the put() method:

HashMap<Integer, Cat> cats = new HashMap<>();
cats.put(1, new Cat());

To retrieve elements from a map, we use the get() method and pass the get() method the key of the element you want to get:

Cat c = cats.get("Arti");

So if you had

HashMap<String, Container> containers = new HashMap<String, Container>();

Then each Map.Entry object inside the hash map's entry set is an instance of Map.Entry<String, Container>

Iterating Maps

When you iterate the map's entries, you retrieve the list of entries using the map's entrySet() method. The entrySet() method actually returns a SET of Map.Entry objects where each Map.Entry models one key-value pair stored in the map.

So if you had a for-each loop such as:

for (Map.Entry<String, Container> element : containers.entrySet()) { 
... 
}

This loop says "For each key-value pair in the hashmap..."

The Map.Entry<K, V> class has a getKey() method: this method returns the key as type <K>, so if you had

for (Map.Entry<String, Container> entry : containers.entrySet()) { 
... 
}

Then entry.getKey() would return the String object that's the index for each entry in the map.

Map.Entry<K, V> also has getValue() method: this method returns the value of the entry as type <V>, so if you had

for (Map.Entry<String, Container> entry : containers.entrySet()) { 
... 
}

Then entry.getValue() would return the Container object stored in an entry of the map.

So you could write a for-each loop that iterates through a hashmap such as:

HashMap<String, Cat> cats = new HashMap<String, Cat>();
cats.put("nomnom", new Cat());
cats.put("Foo Kitty", new Cat("Foo"));
cats.put("Arti", new Cat("Arti", "Tabby"));
for (Map.Entry<String, Cat> entry : cats.entrySet()) {

System.out.printf("Key: %s%nCat: %s%n", entry.getKey(), entry.getValue(); 
// note implied call to Cat's toString() when you print getValue()
}

Practice Exercise

If you need practice with maps, try this exercise:

Create a HashMap of Inventory objects where the key is the inventory item ID value and the value is the actual inventory object. You can just hard-code your map entries, unless you've got some spare time and want to create a JavaFX or Spring Boot application with an input form (which is also good practice)! Write some code to iterate through your HashMap and display each element.