Java Arena
Step 1 of 5

Keys and values

A list keeps its values in a row, and you find a value by its index: get(0), get(1) and so on. Often, though, you want a value by something else. Tickets and luggage tags name airports by three-letter codes: ACC is Accra, LIS is Lisbon. With the codes in one list and the cities in another, finding the city of LIS takes a linear search (module 28): go through the codes until one matches, then take the city at the same index.

A hash map is made for this. It holds pairs: each key (here, a code) is linked to a value (here, a city), and you get a value by giving its key.

import java.util.HashMap;

public class Main {
    public static void main(String[] args) {
        HashMap<String, String> airports = new HashMap<>();
        airports.put("ACC", "Accra");
        airports.put("LIS", "Lisbon");
        airports.put("YVR", "Vancouver");

        System.out.println(airports.get("LIS"));
        System.out.println(airports.get("YVR"));
        System.out.println(airports.get("XYZ"));
    }
}
Output
Lisbon
Vancouver
null
  • HashMap is in java.util, so it needs an import line, like ArrayList.
  • HashMap<String, String> has two types in its angle brackets: first the type of the keys, then the type of the values.
  • put(key, value) adds a pair to the map. get(key) gives the value linked to that key.
  • When the key isn't in the map, get gives null (module 22): this map has no airport with the code XYZ. Nothing crashes, but the program has to be ready for that null.

Why "hash"? From each key, the map works out a number, the key's hash code, and uses it to decide where to keep the pair. To find the key again, get works out the same number and looks right there, instead of going through the pairs one by one. So finding a value by its key usually takes about the same short time whether the map holds ten pairs or a million. (Module 32 says more about hash codes, and part 12 of the course builds a small hash map to show how one works inside.)

Numbers as values

Keys and values can be of other types, but as with the values of a list, they must be class types: Integer, not int. A pantry counts its jars:

HashMap<String, Integer> jars = new HashMap<>();
jars.put("marmalade", 3);
jars.put("plum jam", 5);
jars.put("pickles", 4);

int jam = jars.get("plum jam");
System.out.println("Plum jam: " + jam);
System.out.println("Marmalade and pickles: " + (jars.get("marmalade") + jars.get("pickles")));
System.out.println("Salsa: " + jars.get("salsa"));
Output
Plum jam: 5
Marmalade and pickles: 7
Salsa: null

An Integer from the map turns into an int by itself, as one from a list does. But null isn't a number, so the null of a missing key can't become an int. Storing it in an int variable crashes the program:

import java.util.HashMap;

public class Main {
    public static void main(String[] args) {
        HashMap<String, Integer> jars = new HashMap<>();
        jars.put("marmalade", 3);
        int salsa = jars.get("salsa");
        System.out.println("Salsa: " + salsa);
    }
}
The program crashes with
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.lang.Integer.intValue()" because the return value of "java.util.HashMap.get(Object)" is null
	at Main.main(Main.java:7)

To turn an Integer into an int, Java calls the Integer's intValue() method, and get gave no Integer to call it on.

A value for missing keys: getOrDefault

getOrDefault(key, fallback) gives the value of the key, or the fallback when the key isn't in the map. For counts, 0 is the natural fallback: no salsa in the map means no jars of salsa.

HashMap<String, Integer> jars = new HashMap<>();
jars.put("marmalade", 3);
int marmalade = jars.getOrDefault("marmalade", 0);
int salsa = jars.getOrDefault("salsa", 0);
System.out.println(marmalade + " jars of marmalade, " + salsa + " jars of salsa");
Output
3 jars of marmalade, 0 jars of salsa
  • The fallback has the type of the values. For a HashMap<String, String>, it's a String, such as "unknown".
  • getOrDefault only reads. It doesn't add the key to the map: after it, the map still has no salsa.

Your task

Challenge 1 of 3

A travel desk looks up airport codes. Fill in the blanks. The program reads one airport code. If the map has it, the program prints the code and its city, like NBO is in Nairobi. If it doesn't, it prints No airport with the code and the code. For the input NBO, it prints:

NBO is in Nairobi

Challenge 2

What does this program print? One of the foods isn't in the pantry.

Challenge 3

Chat apps turn shortcodes such as :tada: into emoji. Write the method expand(HashMap<String, String> emoji, String message). The map links shortcodes to the names of their emoji. The method returns the message with every word that is a shortcode in the map replaced by the emoji's name in square brackets. Other words stay as they are. The words of a message are separated by single spaces. The check runs:

HashMap<String, String> emoji = new HashMap<>();
emoji.put(":tada:", "party popper");
emoji.put(":rocket:", "rocket");
emoji.put(":coffee:", "hot beverage");
System.out.println(expand(emoji, "Launch day :rocket: :tada:"));
System.out.println(expand(emoji, ":coffee: first, then :eyes: code"));

and expects:

Launch day [rocket] [party popper]
[hot beverage] first, then :eyes: code