Java Arena
Step 4 of 5

A hash map inside a class

A map can be an instance variable, like a list (module 24). The class creates the map in its constructor, and its methods use it. The rest of the program calls the methods, and doesn't need to know that there's a map inside.

A radio station logs how many times each song was played:

Main.java
public class Main {
    public static void main(String[] args) {
        PlayLog log = new PlayLog();
        log.record("Night Bus");
        log.record("Paper Lanterns");
        log.record("Night Bus");
        System.out.println(log.timesPlayed("Night Bus"));
        System.out.println(log.timesPlayed("Paper Lanterns"));
        System.out.println(log.timesPlayed("Slow River"));
    }
}
PlayLog.java
import java.util.HashMap;

public class PlayLog {
    private HashMap<String, Integer> plays;

    public PlayLog() {
        this.plays = new HashMap<>();
    }

    public void record(String title) {
        int before = this.plays.getOrDefault(title, 0);
        this.plays.put(title, before + 1);
    }

    public int timesPlayed(String title) {
        return this.plays.getOrDefault(title, 0);
    }
}
Output
2
1
0
  • The constructor creates the map. Without this.plays = new HashMap<>();, the instance variable would be null (module 22), and the first record would crash with a NullPointerException.
  • record is the way to count with a map: get the count so far, with 0 for a song that hasn't been played yet, and put back one more. The put replaces the old count, since a key has only one value.
  • timesPlayed gives 0 for a song that was never played, not null, so the caller can use the answer as a number right away.

The count can also be written with containsKey. It does the same:

if (this.plays.containsKey(title)) {
    this.plays.put(title, this.plays.get(title) + 1);
} else {
    this.plays.put(title, 1);
}

Tidy the keys in one place

When the keys come from people, the class can tidy every key itself. A private method keeps the tidying in one place, and every method that uses a key calls it, so a title is tidied the same way whether it's recorded or looked up:

public void record(String title) {
    String key = tidy(title);
    this.plays.put(key, this.plays.getOrDefault(key, 0) + 1);
}

public int timesPlayed(String title) {
    return this.plays.getOrDefault(tidy(title), 0);
}

private String tidy(String title) {
    return title.trim().toLowerCase();
}

Now record("Night Bus") and record(" night bus") count the same song, and timesPlayed("NIGHT BUS") finds it. A method that forgot to call tidy would look for another key, and find nothing.

Your task

Challenge 1 of 3

An airport's baggage storage keeps travelers' bags on numbered shelves. Each bag gets a tag such as B-417, and the staff type the tags in any form: b-417 must find the same bag. Write the class BagStorage, which keeps the shelf of each bag in a HashMap<String, Integer>, with the tags as keys. Tidy every tag with trim() and toUpperCase() before it's used as a key. A private method tidy keeps that in one place.

  • The constructor creates the map.
  • leave(String tag, int shelf) puts the bag on the shelf. When a bag with that tag is already stored, the staff have moved it: the method gives back the shelf it was on before. For a new bag, it gives back -1.
  • collect(String tag) is for a traveler who comes back for a bag. It gives back the shelf to fetch the bag from, and after that the bag isn't stored anymore. For a tag that isn't stored, it gives back -1.
  • bagsStored() returns how many bags are stored.

Main.java is a test drive, and prints:

-1
-1
3
2
1 -1 1

Challenge 2

A radio station keeps a separate play log for its morning show and for its evening show, with the PlayLog class from above and one more method, songs(), which returns how many different songs the log has. What does this program print?

Challenge 3

A museum's audio guide keeps two maps with the same keys, the stop numbers: one for the title of each stop, and one for how many times each stop has been played. Write the class AudioGuide:

  • The constructor creates both maps.
  • addStop(int number, String title) adds a stop.
  • play(int number) returns the stop's title and counts one more play of the stop. For a number with no stop, it returns No stop and the number, and counts nothing.
  • playsOf(int number) returns how many times the stop has been played: 0 for a stop that hasn't been played yet, and for a number with no stop.

The test drive in Main.java prints:

Bronze Horse
Bronze Horse
No stop 72
2 0 0