{"id":"objects-with-lists-finding","slug":"finding-an-object","title":"Finding an object on the list","text":"A method can also go through the list to find one object and return it: the largest, or the first one that matches. Its return type is then the class of the objects. When there's nothing to return, it returns `null`, \"no object\" (module 22):\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        Bookshelf shelf = new Bookshelf(\"Study\");\n        shelf.add(new Book(\"Emma\", \"Austen\", 474));\n        shelf.add(new Book(\"Kindred\", \"Butler\", 264));\n        shelf.add(new Book(\"Middlemarch\", \"Eliot\", 880));\n        System.out.println(\"Thickest: \" + shelf.thickest());\n        Book found = shelf.find(\"Kindred\");\n        if (found != null) {\n            System.out.println(\"Found it, by \" + found.getAuthor());\n        }\n        if (shelf.find(\"Ulysses\") == null) {\n            System.out.println(\"No Ulysses here\");\n        }\n        Bookshelf hall = new Bookshelf(\"Hallway\");\n        System.out.println(hall.thickest());\n    }\n}\n// ==== Bookshelf.java ====\nimport java.util.ArrayList;\n\npublic class Bookshelf {\n    private String room;\n    private ArrayList<Book> books;\n\n    public Bookshelf(String room) {\n        this.room = room;\n        this.books = new ArrayList<>();\n    }\n\n    public void add(Book book) {\n        this.books.add(book);\n    }\n\n    public Book thickest() {\n        if (this.books.isEmpty()) {\n            return null;\n        }\n        Book thickest = this.books.get(0);\n        for (Book book : this.books) {\n            if (book.getPages() > thickest.getPages()) {\n                thickest = book;\n            }\n        }\n        return thickest;\n    }\n\n    public Book find(String title) {\n        for (Book book : this.books) {\n            if (book.getTitle().equals(title)) {\n                return book;\n            }\n        }\n        return null;\n    }\n}\n// ==== Book.java ====\npublic class Book {\n    private String title;\n    private String author;\n    private int pages;\n\n    public Book(String title, String author, int pages) {\n        this.title = title;\n        this.author = author;\n        this.pages = pages;\n    }\n\n    public String getTitle() {\n        return this.title;\n    }\n\n    public String getAuthor() {\n        return this.author;\n    }\n\n    public int getPages() {\n        return this.pages;\n    }\n\n    public String toString() {\n        return this.title + \" by \" + this.author + \", \" + this.pages + \" pages\";\n    }\n}\n```\n\n```output\nThickest: Middlemarch by Eliot, 880 pages\nFound it, by Butler\nNo Ulysses here\nnull\n```\n\n- `thickest` keeps the thickest book so far in a local variable of type Book, starting with the first book on the list. Each book with more pages takes its place. This is module 13's search for the largest value, with objects: the pages decide, but the whole Book is kept.\n- Starting from `this.books.get(0)` needs a first book, so the empty check comes first. Without it, `get(0)` on an empty list would crash with an IndexOutOfBoundsException.\n- With `>`, a book takes the kept one's place only when it's thicker, so of two equally thick books, the first one wins. With `>=`, the last one would.\n- `find` returns the book as soon as it finds it, which also ends the loop. `return null` after the loop runs only when no book matched.\n\n### Checking the result\n\nA method that may return `null` puts a job on its caller: check before using the result. `found.getAuthor()` would crash with a NullPointerException if `found` were `null`, so `main` checks `found != null` first. Printing a `null` is fine, though: `System.out.println(hall.thickest())` prints `null`.\n\nThe method returns the object itself, not a copy. `shelf.find(\"Emma\") == shelf.find(\"Emma\")` is `true`: both calls return a reference to the one Book on the shelf. So if Book could change, a change made through the returned reference would change the book on the shelf.\n","task":"A hotel keeps a list of its rooms. `Room.java` is ready: a room has a number and a number of beds, with the getter `getBeds()`. In `Hotel.java`, write the method `findRoom(int people)`: it returns the first room on the list with at least that many beds, or `null` when there's no such room. The check runs:\n\n```java\nHotel hotel = new Hotel();\nhotel.add(new Room(101, 1));\nhotel.add(new Room(102, 2));\nhotel.add(new Room(201, 4));\nSystem.out.println(hotel.findRoom(2));\nSystem.out.println(hotel.findRoom(3));\nSystem.out.println(hotel.findRoom(5));\n```\n\nand expects:\n\n```\nRoom 102, 2 beds\nRoom 201, 4 beds\nnull\n```\n","kind":"code","seed":"// ==== Hotel.java ====\nimport java.util.ArrayList;\n\npublic class Hotel {\n    private ArrayList<Room> rooms;\n\n    public Hotel() {\n        this.rooms = new ArrayList<>();\n    }\n\n    public void add(Room room) {\n        this.rooms.add(room);\n    }\n\n    // Write the findRoom method here.\n}\n\n// ==== Room.java ====\npublic class Room {\n    private int number;\n    private int beds;\n\n    public Room(int number, int beds) {\n        this.number = number;\n        this.beds = beds;\n    }\n\n    public int getNumber() {\n        return this.number;\n    }\n\n    public int getBeds() {\n        return this.beds;\n    }\n\n    public String toString() {\n        return \"Room \" + this.number + \", \" + this.beds + \" beds\";\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Hotel hotel = new Hotel();\n        hotel.add(new Room(101, 1));\n        hotel.add(new Room(102, 2));\n        hotel.add(new Room(201, 4));\n        System.out.println(hotel.findRoom(2));\n        System.out.println(hotel.findRoom(3));\n        System.out.println(hotel.findRoom(5));\n    }\n}\n","solution":"// ==== Hotel.java ====\nimport java.util.ArrayList;\n\npublic class Hotel {\n    private ArrayList<Room> rooms;\n\n    public Hotel() {\n        this.rooms = new ArrayList<>();\n    }\n\n    public void add(Room room) {\n        this.rooms.add(room);\n    }\n\n    public Room findRoom(int people) {\n        for (Room room : this.rooms) {\n            if (room.getBeds() >= people) {\n                return room;\n            }\n        }\n        return null;\n    }\n}\n\n// ==== Room.java ====\npublic class Room {\n    private int number;\n    private int beds;\n\n    public Room(int number, int beds) {\n        this.number = number;\n        this.beds = beds;\n    }\n\n    public int getNumber() {\n        return this.number;\n    }\n\n    public int getBeds() {\n        return this.beds;\n    }\n\n    public String toString() {\n        return \"Room \" + this.number + \", \" + this.beds + \" beds\";\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Hotel hotel = new Hotel();\n        hotel.add(new Room(101, 1));\n        hotel.add(new Room(102, 2));\n        hotel.add(new Room(201, 4));\n        System.out.println(hotel.findRoom(2));\n        System.out.println(hotel.findRoom(3));\n        System.out.println(hotel.findRoom(5));\n    }\n}\n","hints":["The method's return type is the class of what it finds. Go through the rooms and return the first one that's big enough. If the loop ends without returning, no room was.","`public Room findRoom(int people) {`, then in `for (Room room : this.rooms)`, `if (room.getBeds() >= people) { return room; }`. After the loop: `return null;`."],"tests":[{"name":"Test 1","stdin":"","call":"Hotel hotel = new Hotel();\nhotel.add(new Room(101, 1));\nhotel.add(new Room(102, 2));\nhotel.add(new Room(201, 4));\nSystem.out.println(hotel.findRoom(2));\nSystem.out.println(hotel.findRoom(3));\nSystem.out.println(hotel.findRoom(5));\n","expect":"Room 102, 2 beds\nRoom 201, 4 beds\nnull","hidden":false},{"name":"Test 2","stdin":"","call":"Hotel hotel = new Hotel();\nSystem.out.println(hotel.findRoom(1));\nRoom single = new Room(7, 1);\nhotel.add(single);\nhotel.add(new Room(8, 1));\nSystem.out.println(hotel.findRoom(1) == single);\nSystem.out.println(hotel.findRoom(1).getNumber());\n","expect":"null\ntrue\n7","hidden":true},{"name":"Test 3","stdin":"","call":"Hotel hotel = new Hotel();\nhotel.add(new Room(301, 6));\nhotel.add(new Room(302, 3));\nSystem.out.println(hotel.findRoom(3));\nSystem.out.println(hotel.findRoom(6));\nSystem.out.println(hotel.findRoom(7));\n","expect":"Room 301, 6 beds\nRoom 301, 6 beds\nnull","hidden":true}],"require":[{"pattern":"\\bpublic\\s+Room\\s+findRoom\\s*\\(\\s*int\\s+\\w+\\s*\\)","message":"Write the method as `public Room findRoom(int people)`."}],"forbid":[],"more":[{"task":"What does this program print? `find` and `oldest` both return a Horse from the stable's list, or `null`.\n","kind":"predict","seed":"public class Main {\n    public static void main(String[] args) {\n        Stable stable = new Stable();\n        stable.add(new Horse(\"Storm\", 7));\n        stable.add(new Horse(\"Pepper\", 6));\n        Horse pepper = stable.find(\"Pepper\");\n        pepper.birthday();\n        pepper.birthday();\n        System.out.println(stable.oldest());\n        System.out.println(stable.find(\"Ghost\"));\n        System.out.println(stable.find(\"Storm\") == stable.oldest());\n    }\n}\n// ==== Stable.java ====\nimport java.util.ArrayList;\n\npublic class Stable {\n    private ArrayList<Horse> horses;\n\n    public Stable() {\n        this.horses = new ArrayList<>();\n    }\n\n    public void add(Horse horse) {\n        this.horses.add(horse);\n    }\n\n    public Horse find(String name) {\n        for (Horse horse : this.horses) {\n            if (horse.getName().equals(name)) {\n                return horse;\n            }\n        }\n        return null;\n    }\n\n    public Horse oldest() {\n        if (this.horses.isEmpty()) {\n            return null;\n        }\n        Horse oldest = this.horses.get(0);\n        for (Horse horse : this.horses) {\n            if (horse.getAge() > oldest.getAge()) {\n                oldest = horse;\n            }\n        }\n        return oldest;\n    }\n}\n// ==== Horse.java ====\npublic class Horse {\n    private String name;\n    private int age;\n\n    public Horse(String name, int age) {\n        this.name = name;\n        this.age = age;\n    }\n\n    public String getName() {\n        return this.name;\n    }\n\n    public int getAge() {\n        return this.age;\n    }\n\n    public void birthday() {\n        this.age++;\n    }\n\n    public String toString() {\n        return this.name + \", \" + this.age + \" years\";\n    }\n}\n","solution":"public class Main {\n    public static void main(String[] args) {\n        Stable stable = new Stable();\n        stable.add(new Horse(\"Storm\", 7));\n        stable.add(new Horse(\"Pepper\", 6));\n        Horse pepper = stable.find(\"Pepper\");\n        pepper.birthday();\n        pepper.birthday();\n        System.out.println(stable.oldest());\n        System.out.println(stable.find(\"Ghost\"));\n        System.out.println(stable.find(\"Storm\") == stable.oldest());\n    }\n}\n// ==== Stable.java ====\nimport java.util.ArrayList;\n\npublic class Stable {\n    private ArrayList<Horse> horses;\n\n    public Stable() {\n        this.horses = new ArrayList<>();\n    }\n\n    public void add(Horse horse) {\n        this.horses.add(horse);\n    }\n\n    public Horse find(String name) {\n        for (Horse horse : this.horses) {\n            if (horse.getName().equals(name)) {\n                return horse;\n            }\n        }\n        return null;\n    }\n\n    public Horse oldest() {\n        if (this.horses.isEmpty()) {\n            return null;\n        }\n        Horse oldest = this.horses.get(0);\n        for (Horse horse : this.horses) {\n            if (horse.getAge() > oldest.getAge()) {\n                oldest = horse;\n            }\n        }\n        return oldest;\n    }\n}\n// ==== Horse.java ====\npublic class Horse {\n    private String name;\n    private int age;\n\n    public Horse(String name, int age) {\n        this.name = name;\n        this.age = age;\n    }\n\n    public String getName() {\n        return this.name;\n    }\n\n    public int getAge() {\n        return this.age;\n    }\n\n    public void birthday() {\n        this.age++;\n    }\n\n    public String toString() {\n        return this.name + \", \" + this.age + \" years\";\n    }\n}\n","hints":["`find` returns the Horse object on the list, not a copy. So the two birthdays through `pepper` make the stable's Pepper 8, older than Storm.","There's no horse called Ghost, so `find` returns `null`, and printing it prints `null`. Storm isn't the oldest any more, so the two calls return different objects."],"tests":[{"name":"Output","stdin":"","expect":"Pepper, 8 years\nnull\nfalse","hidden":false}],"require":[],"forbid":[],"lines":["Pepper, 8 years","null","false"]},{"task":"An election has a list of candidates. `Candidate.java` is ready: a candidate has a name and a number of votes that starts at 0, with `getName()`, `getVotes()` and `addVote()`. In `Election.java`, write two methods:\n\n- `vote(String name)` gives one vote to the candidate with that name. A name that isn't a candidate's does nothing.\n- `leader()` returns the candidate with the most votes. When there are no candidates, or when two or more share the most votes, there's no leader, and it returns `null`.\n\nThe check runs:\n\n```java\nElection election = new Election();\nelection.add(new Candidate(\"Ines\"));\nelection.add(new Candidate(\"Omar\"));\nelection.add(new Candidate(\"Yuki\"));\nSystem.out.println(election.leader());\nelection.vote(\"Omar\");\nelection.vote(\"Ines\");\nelection.vote(\"Omar\");\nelection.vote(\"Zed\");\nSystem.out.println(election.leader());\n```\n\nand expects:\n\n```\nnull\nOmar, 2 votes\n```\n","kind":"code","seed":"// ==== Election.java ====\nimport java.util.ArrayList;\n\npublic class Election {\n    private ArrayList<Candidate> candidates;\n\n    public Election() {\n        this.candidates = new ArrayList<>();\n    }\n\n    public void add(Candidate candidate) {\n        this.candidates.add(candidate);\n    }\n\n    // Write the methods vote and leader here.\n}\n\n// ==== Candidate.java ====\npublic class Candidate {\n    private String name;\n    private int votes;\n\n    public Candidate(String name) {\n        this.name = name;\n        this.votes = 0;\n    }\n\n    public String getName() {\n        return this.name;\n    }\n\n    public int getVotes() {\n        return this.votes;\n    }\n\n    public void addVote() {\n        this.votes++;\n    }\n\n    public String toString() {\n        return this.name + \", \" + this.votes + \" votes\";\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Election election = new Election();\n        election.add(new Candidate(\"Ines\"));\n        election.add(new Candidate(\"Omar\"));\n        election.add(new Candidate(\"Yuki\"));\n        System.out.println(election.leader());\n        election.vote(\"Omar\");\n        election.vote(\"Ines\");\n        election.vote(\"Omar\");\n        election.vote(\"Zed\");\n        System.out.println(election.leader());\n    }\n}\n","solution":"// ==== Election.java ====\nimport java.util.ArrayList;\n\npublic class Election {\n    private ArrayList<Candidate> candidates;\n\n    public Election() {\n        this.candidates = new ArrayList<>();\n    }\n\n    public void add(Candidate candidate) {\n        this.candidates.add(candidate);\n    }\n\n    public void vote(String name) {\n        for (Candidate candidate : this.candidates) {\n            if (candidate.getName().equals(name)) {\n                candidate.addVote();\n            }\n        }\n    }\n\n    public Candidate leader() {\n        Candidate best = null;\n        boolean shared = false;\n        for (Candidate candidate : this.candidates) {\n            if (best == null || candidate.getVotes() > best.getVotes()) {\n                best = candidate;\n                shared = false;\n            } else if (candidate.getVotes() == best.getVotes()) {\n                shared = true;\n            }\n        }\n        if (shared) {\n            return null;\n        }\n        return best;\n    }\n}\n\n// ==== Candidate.java ====\npublic class Candidate {\n    private String name;\n    private int votes;\n\n    public Candidate(String name) {\n        this.name = name;\n        this.votes = 0;\n    }\n\n    public String getName() {\n        return this.name;\n    }\n\n    public int getVotes() {\n        return this.votes;\n    }\n\n    public void addVote() {\n        this.votes++;\n    }\n\n    public String toString() {\n        return this.name + \", \" + this.votes + \" votes\";\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Election election = new Election();\n        election.add(new Candidate(\"Ines\"));\n        election.add(new Candidate(\"Omar\"));\n        election.add(new Candidate(\"Yuki\"));\n        System.out.println(election.leader());\n        election.vote(\"Omar\");\n        election.vote(\"Ines\");\n        election.vote(\"Omar\");\n        election.vote(\"Zed\");\n        System.out.println(election.leader());\n    }\n}\n","hints":["`vote` goes through the candidates, and calls `candidate.addVote()` on the one whose name `equals` the name given. The vote changes the Candidate object on the list itself.","In `leader`, keep the best candidate so far (starting at `null`) and a boolean `shared`. A candidate with more votes than the best becomes the best, and `shared` goes back to false; one with just as many votes sets `shared` to true. After the loop, return `null` if `shared` is true, and the best one otherwise."],"tests":[{"name":"Test 1","stdin":"","call":"Election election = new Election();\nelection.add(new Candidate(\"Ines\"));\nelection.add(new Candidate(\"Omar\"));\nelection.add(new Candidate(\"Yuki\"));\nSystem.out.println(election.leader());\nelection.vote(\"Omar\");\nelection.vote(\"Ines\");\nelection.vote(\"Omar\");\nelection.vote(\"Zed\");\nSystem.out.println(election.leader());\n","expect":"null\nOmar, 2 votes","hidden":false},{"name":"Test 2","stdin":"","call":"Election election = new Election();\nSystem.out.println(election.leader());\nCandidate solo = new Candidate(\"Solo\");\nelection.add(solo);\nSystem.out.println(election.leader() == solo);\nelection.vote(\"So\" + \"lo\");\nSystem.out.println(solo);\n","expect":"null\ntrue\nSolo, 1 votes","hidden":true},{"name":"Test 3","stdin":"","call":"Election election = new Election();\nelection.add(new Candidate(\"Ann\"));\nelection.add(new Candidate(\"Bea\"));\nelection.add(new Candidate(\"Cal\"));\nelection.vote(\"Ann\");\nelection.vote(\"Cal\");\nSystem.out.println(election.leader());\nelection.vote(\"Cal\");\nSystem.out.println(election.leader());\nelection.vote(\"Bea\");\nelection.vote(\"Bea\");\nSystem.out.println(election.leader());\nelection.vote(\"Bea\");\nSystem.out.println(election.leader());\n","expect":"null\nCal, 2 votes\nnull\nBea, 3 votes","hidden":true},{"name":"Test 4","stdin":"","call":"Election election = new Election();\nelection.add(new Candidate(\"Dov\"));\nelection.add(new Candidate(\"Eve\"));\nelection.vote(\"Eve\");\nelection.vote(\"Eve\");\nelection.vote(\"Dov\");\nelection.vote(\"Dov\");\nelection.vote(\"Dov\");\nSystem.out.println(election.leader());\n","expect":"Dov, 3 votes","hidden":true}],"require":[{"pattern":"\\bpublic\\s+void\\s+vote\\s*\\(\\s*String\\s+\\w+\\s*\\)","message":"Write the method as `public void vote(String name)`."},{"pattern":"\\bpublic\\s+Candidate\\s+leader\\s*\\(\\s*\\)","message":"Write the method as `public Candidate leader()`."},{"pattern":"\\.addVote\\s*\\(\\s*\\)","message":"Give the vote with the candidate's `addVote()`."}],"forbid":[]}]}