Java Arena
Step 3 of 5

Objects as values

The values of a map can be objects of your own class. Then the map finds a whole object by its key. A museum's audio guide works this way: each exhibit has a number on a small sign, and visitors type the number into the guide to hear about the exhibit. The keys are the numbers, and the values are GuideStop objects.

Main.java
import java.util.HashMap;

public class Main {
    public static void main(String[] args) {
        HashMap<Integer, GuideStop> stops = new HashMap<>();
        GuideStop harbor = new GuideStop(12, "The Harbor at Dawn", 3);
        GuideStop horse = new GuideStop(27, "Bronze Horse", 5);
        stops.put(harbor.getNumber(), harbor);
        stops.put(horse.getNumber(), horse);

        GuideStop stop = stops.get(27);
        System.out.println(stop.getTitle() + " is in room " + stop.getRoom());
        stop.listen();
        stops.get(27).listen();
        stops.get(12).listen();
        System.out.println(stops.get(27));
        System.out.println(stops.get(12));
    }
}
GuideStop.java
public class GuideStop {
    private int number;
    private String title;
    private int room;
    private int listens;

    public GuideStop(int number, String title, int room) {
        this.number = number;
        this.title = title;
        this.room = room;
        this.listens = 0;
    }

    public int getNumber() {
        return this.number;
    }

    public String getTitle() {
        return this.title;
    }

    public int getRoom() {
        return this.room;
    }

    public void listen() {
        this.listens++;
    }

    public String toString() {
        return this.title + " (room " + this.room + "), listens: " + this.listens;
    }
}
Output
Bronze Horse is in room 5
Bronze Horse (room 5), listens: 2
The Harbor at Dawn (room 3), listens: 1
  • The key comes from the object itself: stops.put(harbor.getNumber(), harbor). That's common: a product found by its code, a user by their username. The key is then kept twice, in the object and in the map, and the two should match.
  • A map keeps references to its objects, as a list does (module 22). stops.get(27) gives a reference to the Bronze Horse object in the map, not a copy of it. So stop.listen() changes the object in the map, and there's no need to put it back.
  • stops.get(27).listen() finds the object and calls its method in one go. It's the same object again, so it now has 2 listens.

A number with no stop

A visitor types 72 instead of 27. The map has no such key, get gives null, and calling a method on null crashes:

Main.java
import java.util.HashMap;

public class Main {
    public static void main(String[] args) {
        HashMap<Integer, GuideStop> stops = new HashMap<>();
        GuideStop horse = new GuideStop(27, "Bronze Horse", 5);
        stops.put(horse.getNumber(), horse);
        stops.get(72).listen();
    }
}
GuideStop.java
public class GuideStop {
    private int number;
    private String title;
    private int room;
    private int listens;

    public GuideStop(int number, String title, int room) {
        this.number = number;
        this.title = title;
        this.room = room;
        this.listens = 0;
    }

    public int getNumber() {
        return this.number;
    }

    public void listen() {
        this.listens++;
    }
}
The program crashes with
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "GuideStop.listen()" because the return value of "java.util.HashMap.get(Object)" is null
	at Main.main(Main.java:8)

When a key may be missing, keep what get gives in a variable, and check it before calling anything on it:

GuideStop stop = stops.get(number);
if (stop == null) {
    System.out.println("No stop with the number " + number);
} else {
    stop.listen();
    System.out.println(stop);
}

Your task

Challenge 1 of 3

Airport.java is ready: an airport has a code, a city and a country, with getters and a toString. In Main.java, write the method byCode(ArrayList<Airport> airports). It makes a new HashMap<String, Airport>, puts every airport of the list in it with the airport's code as the key, and returns the map. The check runs:

ArrayList<Airport> list = new ArrayList<>();
list.add(new Airport("OSL", "Oslo", "Norway"));
list.add(new Airport("ICN", "Seoul", "South Korea"));
list.add(new Airport("MEX", "Mexico City", "Mexico"));
HashMap<String, Airport> airports = byCode(list);
System.out.println(airports.get("ICN"));
System.out.println(airports.get("MEX").getCity());
System.out.println(airports.size());

and expects:

Seoul, South Korea (ICN)
Mexico City
3

Challenge 2

A radio station finds the tracks it plays by a key, and one track got two keys: its title, and a short name. What does this program print?

Challenge 3

A small hotel keeps its rooms in a HashMap<Integer, Room>, with the room numbers as keys. Room.java is ready: a room is free until a guest checks in, and it has the methods isFree(), checkIn(String guest) and getGuest(). In Main.java, write the method checkInGuest(HashMap<Integer, Room> rooms, int number, String guest). It returns:

  • No room and the number, when the hotel has no room with that number,
  • Room , the number and is taken, when someone is already in the room,
  • otherwise, it checks the guest in to the room and returns Welcome, , the guest, ! Room and the number.

The check runs:

HashMap<Integer, Room> rooms = new HashMap<>();
rooms.put(101, new Room(101));
rooms.put(102, new Room(102));
System.out.println(checkInGuest(rooms, 102, "Achebe"));
System.out.println(checkInGuest(rooms, 102, "Moreau"));
System.out.println(checkInGuest(rooms, 105, "Moreau"));
System.out.println(rooms.get(102));

and expects:

Welcome, Achebe! Room 102
Room 102 is taken
No room 105
Room 102: Achebe