{"id":"larger-programs-end-of-course-one","slug":"end-of-java-programming-1","title":"The end of Java Programming I","text":"This step ends the material of the MOOC's seventh part, and with it Java Programming I, the first half of the course. First, this module in one list. When a program is bigger than a screen:\n\n1. Start from a description, and find its parts: a class for the data, a class for the logic, and the part that reads input and prints.\n2. Write down the rules for input before writing code: what ends it, what's valid, and what to print when nothing is.\n3. Build the data class first, then the logic, and the input part last. Try each piece with a test drive, and use placeholders for methods that aren't written yet.\n4. Let the logic answer with return values, `null` and `false` included, and let the input part turn those answers into messages.\n5. Read every line of a command before checking any of it, and answer bad input instead of crashing.\n\n### What Java Programming I covered\n\nEvery program in this module was built from the tools of the earlier ones. Here they are, part by part:\n\n- **Part 1:** printing, reading input with a Scanner, variables and their types, calculating, and choosing with `if`, `else if` and conditions joined with `&&`, `||` and `!`.\n- **Part 2:** repeating with `while` and `for`, `break` and `continue`, and dividing a program into methods with parameters and return values.\n- **Part 3:** finding bugs, lists and arrays, and taking text apart with the String methods and `split`.\n- **Part 4:** classes and objects, with constructors, getters and `toString`, lists of objects, and reading files.\n- **Part 5:** designing classes, overloading, primitive and reference variables, `null`, objects that use other objects, and `equals`.\n- **Part 6:** lists inside objects, a user interface kept apart from the program's logic, and unit tests with JUnit.\n- **Part 7:** procedural and object-oriented programs side by side, sorting and searching, and this module's larger programs.\n\n### A final program\n\nThis step's challenges put many of those tools into one program. The board-game club of step 1 runs a league: after every game, each player gets 0 to 10 league points, and the club writes them into the file `league.csv`, one line per player and game, like `Mia,8`. The program reads the file (part 4), keeps the players in a list inside a logic object and each player's points in a list inside the player (part 6), finds players by name and picks the leader (parts 3 and 5), sorts their names (part 7), and answers commands, bad input included (part 6 and this module). The plan:\n\n| Part | Class | Its job |\n| --- | --- | --- |\n| The data | `Player` | a player's name and their points from each game |\n| The logic | `League` | the players: find one, add a game's points, the leader, the names in order |\n| Input and output | `Main` and `UserInterface` | read the file, then answer the commands |\n\nHere's `Player`, ready for both challenges:\n\n```java\nimport java.util.ArrayList;\n\npublic class Player {\n    private String name;\n    private ArrayList<Integer> games;\n\n    public Player(String name) {\n        this.name = name;\n        this.games = new ArrayList<>();\n    }\n\n    public String getName() {\n        return this.name;\n    }\n\n    public void addGame(int points) {\n        this.games.add(points);\n    }\n\n    public int total() {\n        int total = 0;\n        for (int points : this.games) {\n            total += points;\n        }\n        return total;\n    }\n\n    public String toString() {\n        return this.name + \", total \" + this.total() + \", games \" + this.games;\n    }\n}\n```\n\n### What comes next\n\nJava Programming II continues from part 8. It opens with a short recap of parts 1 to 7, and then brings the **hash map**: a collection that finds a value by its key, such as a phone number by a person's name. After that, its parts go on to inheritance and interfaces, streams, exceptions, writing files and graphical user interfaces, among other things. This site will add those modules later. Part 7, and with it Java Programming I, closes with [the MOOC's conclusion page](https://java-programming.mooc.fi/part-7/4-java-programming) on its own site.\n","task":"The league's logic. `Player.java` is the class above, and `Main.java` is ready: it reads `league.csv` and gives each line to `add`, and then it tries the other methods out. In `League.java`, replace the placeholders:\n\n- `find(String name)` returns the player with that name, or `null`.\n- `add(String playerName, int points)` adds a game's points to the player. When there's no player by that name yet, it first creates one and adds it to the list.\n- `leader()` returns the player with the most points in all, or `null` when there are no players. If two players have the same total, the one added first.\n- `playerNames()` returns a new list of the players' names in alphabetical order. Sort it with `Collections.sort`.\n\nLeague doesn't print anything. For the file shown below, the program prints:\n\n```\nPlayers: [Jonas, Mia, Priya]\nLeader: Mia, total 23, games [8, 7, 8]\nPriya, total 22, games [6, 9, 7]\nnull\n```\n","kind":"code","seed":"// ==== League.java ====\nimport java.util.ArrayList;\nimport java.util.Collections;\n\npublic class League {\n    private ArrayList<Player> players;\n\n    public League() {\n        this.players = new ArrayList<>();\n    }\n\n    public Player find(String name) {\n        // Replace the placeholders with the real code.\n        return null;\n    }\n\n    public void add(String playerName, int points) {\n    }\n\n    public Player leader() {\n        return null;\n    }\n\n    public ArrayList<String> playerNames() {\n        return new ArrayList<>();\n    }\n}\n\n// ==== Player.java ====\nimport java.util.ArrayList;\n\npublic class Player {\n    private String name;\n    private ArrayList<Integer> games;\n\n    public Player(String name) {\n        this.name = name;\n        this.games = new ArrayList<>();\n    }\n\n    public String getName() {\n        return this.name;\n    }\n\n    public void addGame(int points) {\n        this.games.add(points);\n    }\n\n    public int total() {\n        int total = 0;\n        for (int points : this.games) {\n            total += points;\n        }\n        return total;\n    }\n\n    public String toString() {\n        return this.name + \", total \" + this.total() + \", games \" + this.games;\n    }\n}\n\n// ==== Main.java ====\nimport java.nio.file.Paths;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        League league = readLeague(\"league.csv\");\n        System.out.println(\"Players: \" + league.playerNames());\n        System.out.println(\"Leader: \" + league.leader());\n        System.out.println(league.find(\"Priya\"));\n        System.out.println(league.find(\"Pia\"));\n    }\n\n    public static League readLeague(String fileName) {\n        League league = new League();\n        try (Scanner scanner = new Scanner(Paths.get(fileName))) {\n            while (scanner.hasNextLine()) {\n                String[] parts = scanner.nextLine().split(\",\");\n                if (parts.length < 2) {\n                    continue;\n                }\n                league.add(parts[0], Integer.valueOf(parts[1]));\n            }\n        } catch (Exception e) {\n            System.out.println(\"Error: \" + e.getMessage());\n        }\n        return league;\n    }\n}\n","solution":"// ==== League.java ====\nimport java.util.ArrayList;\nimport java.util.Collections;\n\npublic class League {\n    private ArrayList<Player> players;\n\n    public League() {\n        this.players = new ArrayList<>();\n    }\n\n    public Player find(String name) {\n        // Replace the placeholders with the real code.\n        for (Player player : this.players) {\n            if (player.getName().equals(name)) {\n                return player;\n            }\n        }\n        return null;\n    }\n\n    public void add(String playerName, int points) {\n        Player player = this.find(playerName);\n        if (player == null) {\n            player = new Player(playerName);\n            this.players.add(player);\n        }\n        player.addGame(points);\n    }\n\n    public Player leader() {\n        Player leader = null;\n        for (Player player : this.players) {\n            if (leader == null || player.total() > leader.total()) {\n                leader = player;\n            }\n        }\n        return leader;\n    }\n\n    public ArrayList<String> playerNames() {\n        ArrayList<String> names = new ArrayList<>();\n        for (Player player : this.players) {\n            names.add(player.getName());\n        }\n        Collections.sort(names);\n        return names;\n    }\n}\n\n// ==== Player.java ====\nimport java.util.ArrayList;\n\npublic class Player {\n    private String name;\n    private ArrayList<Integer> games;\n\n    public Player(String name) {\n        this.name = name;\n        this.games = new ArrayList<>();\n    }\n\n    public String getName() {\n        return this.name;\n    }\n\n    public void addGame(int points) {\n        this.games.add(points);\n    }\n\n    public int total() {\n        int total = 0;\n        for (int points : this.games) {\n            total += points;\n        }\n        return total;\n    }\n\n    public String toString() {\n        return this.name + \", total \" + this.total() + \", games \" + this.games;\n    }\n}\n\n// ==== Main.java ====\nimport java.nio.file.Paths;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        League league = readLeague(\"league.csv\");\n        System.out.println(\"Players: \" + league.playerNames());\n        System.out.println(\"Leader: \" + league.leader());\n        System.out.println(league.find(\"Priya\"));\n        System.out.println(league.find(\"Pia\"));\n    }\n\n    public static League readLeague(String fileName) {\n        League league = new League();\n        try (Scanner scanner = new Scanner(Paths.get(fileName))) {\n            while (scanner.hasNextLine()) {\n                String[] parts = scanner.nextLine().split(\",\");\n                if (parts.length < 2) {\n                    continue;\n                }\n                league.add(parts[0], Integer.valueOf(parts[1]));\n            }\n        } catch (Exception e) {\n            System.out.println(\"Error: \" + e.getMessage());\n        }\n        return league;\n    }\n}\n","hints":["`find` is the loop of step 3's `FoodBank.find`. `add` calls `this.find(playerName)` first. When that's `null`, it makes `new Player(playerName)`, adds it to `this.players` and keeps it in the variable, and then calls `addGame(points)` on the player either way.","`leader` is a best match that starts from `null` and compares `player.total()`, with `>` so that the first of two equal players stays. `playerNames` adds each player's `getName()` to a new `ArrayList<String>`, and calls `Collections.sort(names)` before returning it."],"tests":[{"name":"Test 1","stdin":"","files":{"league.csv":"Mia,8\nPriya,6\nJonas,9\nMia,7\nPriya,9\nJonas,5\nMia,8\nPriya,7\nJonas,8\n"},"expect":"Players: [Jonas, Mia, Priya]\nLeader: Mia, total 23, games [8, 7, 8]\nPriya, total 22, games [6, 9, 7]\nnull","hidden":false},{"name":"Test 2","stdin":"","call":"League q = new League();\nSystem.out.println(q.leader() + \" \" + q.playerNames() + \" \" + q.find(\"Ari\"));\nq.add(\"Zoe\", 5);\nq.add(\"Ari\", 5);\nq.add(\"Zoe\", 0);\nSystem.out.println(q.playerNames() + \" \" + q.leader());\nSystem.out.println(q.find(\"Ari\") + \" \" + q.find(\"ari\"));\n","expect":"null [] null\n[Ari, Zoe] Zoe, total 5, games [5, 0]\nAri, total 5, games [5] null","hidden":true},{"name":"Test 3","stdin":"","call":"League q = new League();\nq.add(\"Nils\", 3);\nq.add(\"Bea\", 10);\nq.add(\"Nils\", 9);\nArrayList<String> names = q.playerNames();\nnames.add(\"Extra\");\nSystem.out.println(q.playerNames() + \" \" + q.leader().getName() + \" \" + q.find(\"Nils\").total());\n","expect":"[Bea, Nils] Nils 12","hidden":true}],"require":[{"pattern":"Collections\\s*\\.\\s*sort\\s*\\(","message":"Sort the names with `Collections.sort`."}],"forbid":[{"pattern":"\\bclass\\s+League\\b[\\s\\S]*\\bSystem\\s*\\.\\s*out\\b[\\s\\S]*\\bclass\\s+Player\\b","message":"League doesn't print. Its methods return their answers, and `main` prints them."}],"more":[{"task":"The league's user interface. `League.java` (with the methods of the previous challenge), `Player.java` and `Main.java` are ready: `main` reads `league.csv` into a League and starts the user interface. In `UserInterface.java`, the loop, `quit`, `leader`, the answer to unknown commands and the lesson's `toNumber` are ready too. Write the two empty branches:\n\n- `add`, then a player's name and a line with the points: the points must be a whole number from 0 to 10, and otherwise print `Points must be a whole number from 0 to 10`. With valid points, add the game's points (a name that's new makes a new player) and print the player.\n- `compare`, then two lines, each with a player's name. Read both lines first. If the first player isn't in the league, print `No player called ` and that name, and otherwise the same for the second. When both are there, print who has more points in all, the one with more points first, like `Priya is ahead of Mia: 24 to 15`. When their totals are the same, print the two names in the order they were typed, like `Mia and Jonas are tied at 15`.\n\nFor the input shown and the file shown below, the program prints:\n\n```\n> Points must be a whole number from 0 to 10\n> Priya, total 24, games [6, 9, 9]\n> Priya is ahead of Mia: 24 to 15\n> No player called Pia\n> Jonas, total 15, games [9, 5, 1]\n> Mia and Jonas are tied at 15\n> Leader: Priya, total 24, games [6, 9, 9]\n> Unknown command: score\n> Good night\n```\n","kind":"code","seed":"// ==== UserInterface.java ====\nimport java.util.Scanner;\n\npublic class UserInterface {\n    private Scanner scanner;\n    private League league;\n\n    public UserInterface(Scanner scanner, League league) {\n        this.scanner = scanner;\n        this.league = league;\n    }\n\n    public void start() {\n        while (true) {\n            System.out.print(\"> \");\n            String command = this.scanner.nextLine();\n            if (command.equals(\"quit\")) {\n                System.out.println(\"Good night\");\n                break;\n            }\n            if (command.equals(\"leader\")) {\n                Player leader = this.league.leader();\n                if (leader == null) {\n                    System.out.println(\"No players yet\");\n                } else {\n                    System.out.println(\"Leader: \" + leader);\n                }\n            } else if (command.equals(\"add\")) {\n                // Write the add command here.\n            } else if (command.equals(\"compare\")) {\n                // Write the compare command here.\n            } else {\n                System.out.println(\"Unknown command: \" + command);\n            }\n        }\n    }\n\n    private int toNumber(String text) {\n        try {\n            return Integer.valueOf(text);\n        } catch (Exception e) {\n            return -1;\n        }\n    }\n}\n\n// ==== League.java ====\nimport java.util.ArrayList;\nimport java.util.Collections;\n\npublic class League {\n    private ArrayList<Player> players;\n\n    public League() {\n        this.players = new ArrayList<>();\n    }\n\n    public Player find(String name) {\n        for (Player player : this.players) {\n            if (player.getName().equals(name)) {\n                return player;\n            }\n        }\n        return null;\n    }\n\n    public void add(String playerName, int points) {\n        Player player = this.find(playerName);\n        if (player == null) {\n            player = new Player(playerName);\n            this.players.add(player);\n        }\n        player.addGame(points);\n    }\n\n    public Player leader() {\n        Player leader = null;\n        for (Player player : this.players) {\n            if (leader == null || player.total() > leader.total()) {\n                leader = player;\n            }\n        }\n        return leader;\n    }\n\n    public ArrayList<String> playerNames() {\n        ArrayList<String> names = new ArrayList<>();\n        for (Player player : this.players) {\n            names.add(player.getName());\n        }\n        Collections.sort(names);\n        return names;\n    }\n}\n\n// ==== Player.java ====\nimport java.util.ArrayList;\n\npublic class Player {\n    private String name;\n    private ArrayList<Integer> games;\n\n    public Player(String name) {\n        this.name = name;\n        this.games = new ArrayList<>();\n    }\n\n    public String getName() {\n        return this.name;\n    }\n\n    public void addGame(int points) {\n        this.games.add(points);\n    }\n\n    public int total() {\n        int total = 0;\n        for (int points : this.games) {\n            total += points;\n        }\n        return total;\n    }\n\n    public String toString() {\n        return this.name + \", total \" + this.total() + \", games \" + this.games;\n    }\n}\n\n// ==== Main.java ====\nimport java.nio.file.Paths;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        League league = readLeague(\"league.csv\");\n        Scanner scanner = new Scanner(System.in);\n        UserInterface ui = new UserInterface(scanner, league);\n        ui.start();\n    }\n\n    public static League readLeague(String fileName) {\n        League league = new League();\n        try (Scanner scanner = new Scanner(Paths.get(fileName))) {\n            while (scanner.hasNextLine()) {\n                String[] parts = scanner.nextLine().split(\",\");\n                if (parts.length < 2) {\n                    continue;\n                }\n                league.add(parts[0], Integer.valueOf(parts[1]));\n            }\n        } catch (Exception e) {\n            System.out.println(\"Error: \" + e.getMessage());\n        }\n        return league;\n    }\n}\n","solution":"// ==== UserInterface.java ====\nimport java.util.Scanner;\n\npublic class UserInterface {\n    private Scanner scanner;\n    private League league;\n\n    public UserInterface(Scanner scanner, League league) {\n        this.scanner = scanner;\n        this.league = league;\n    }\n\n    public void start() {\n        while (true) {\n            System.out.print(\"> \");\n            String command = this.scanner.nextLine();\n            if (command.equals(\"quit\")) {\n                System.out.println(\"Good night\");\n                break;\n            }\n            if (command.equals(\"leader\")) {\n                Player leader = this.league.leader();\n                if (leader == null) {\n                    System.out.println(\"No players yet\");\n                } else {\n                    System.out.println(\"Leader: \" + leader);\n                }\n            } else if (command.equals(\"add\")) {\n                // Write the add command here.\n                String name = this.scanner.nextLine();\n                int points = this.toNumber(this.scanner.nextLine());\n                if (points < 0 || points > 10) {\n                    System.out.println(\"Points must be a whole number from 0 to 10\");\n                } else {\n                    this.league.add(name, points);\n                    System.out.println(this.league.find(name));\n                }\n            } else if (command.equals(\"compare\")) {\n                // Write the compare command here.\n                String first = this.scanner.nextLine();\n                String second = this.scanner.nextLine();\n                Player one = this.league.find(first);\n                Player two = this.league.find(second);\n                if (one == null) {\n                    System.out.println(\"No player called \" + first);\n                } else if (two == null) {\n                    System.out.println(\"No player called \" + second);\n                } else if (one.total() > two.total()) {\n                    System.out.println(first + \" is ahead of \" + second + \": \" + one.total() + \" to \" + two.total());\n                } else if (two.total() > one.total()) {\n                    System.out.println(second + \" is ahead of \" + first + \": \" + two.total() + \" to \" + one.total());\n                } else {\n                    System.out.println(first + \" and \" + second + \" are tied at \" + one.total());\n                }\n            } else {\n                System.out.println(\"Unknown command: \" + command);\n            }\n        }\n    }\n\n    private int toNumber(String text) {\n        try {\n            return Integer.valueOf(text);\n        } catch (Exception e) {\n            return -1;\n        }\n    }\n}\n\n// ==== League.java ====\nimport java.util.ArrayList;\nimport java.util.Collections;\n\npublic class League {\n    private ArrayList<Player> players;\n\n    public League() {\n        this.players = new ArrayList<>();\n    }\n\n    public Player find(String name) {\n        for (Player player : this.players) {\n            if (player.getName().equals(name)) {\n                return player;\n            }\n        }\n        return null;\n    }\n\n    public void add(String playerName, int points) {\n        Player player = this.find(playerName);\n        if (player == null) {\n            player = new Player(playerName);\n            this.players.add(player);\n        }\n        player.addGame(points);\n    }\n\n    public Player leader() {\n        Player leader = null;\n        for (Player player : this.players) {\n            if (leader == null || player.total() > leader.total()) {\n                leader = player;\n            }\n        }\n        return leader;\n    }\n\n    public ArrayList<String> playerNames() {\n        ArrayList<String> names = new ArrayList<>();\n        for (Player player : this.players) {\n            names.add(player.getName());\n        }\n        Collections.sort(names);\n        return names;\n    }\n}\n\n// ==== Player.java ====\nimport java.util.ArrayList;\n\npublic class Player {\n    private String name;\n    private ArrayList<Integer> games;\n\n    public Player(String name) {\n        this.name = name;\n        this.games = new ArrayList<>();\n    }\n\n    public String getName() {\n        return this.name;\n    }\n\n    public void addGame(int points) {\n        this.games.add(points);\n    }\n\n    public int total() {\n        int total = 0;\n        for (int points : this.games) {\n            total += points;\n        }\n        return total;\n    }\n\n    public String toString() {\n        return this.name + \", total \" + this.total() + \", games \" + this.games;\n    }\n}\n\n// ==== Main.java ====\nimport java.nio.file.Paths;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        League league = readLeague(\"league.csv\");\n        Scanner scanner = new Scanner(System.in);\n        UserInterface ui = new UserInterface(scanner, league);\n        ui.start();\n    }\n\n    public static League readLeague(String fileName) {\n        League league = new League();\n        try (Scanner scanner = new Scanner(Paths.get(fileName))) {\n            while (scanner.hasNextLine()) {\n                String[] parts = scanner.nextLine().split(\",\");\n                if (parts.length < 2) {\n                    continue;\n                }\n                league.add(parts[0], Integer.valueOf(parts[1]));\n            }\n        } catch (Exception e) {\n            System.out.println(\"Error: \" + e.getMessage());\n        }\n        return league;\n    }\n}\n","hints":["Each branch reads all its lines before any check, like `log` in the lesson. `add` needs `toNumber`, then the league's `add` and `find`; `compare` needs `find` twice and each player's `total()`.","In `add`, `this.toNumber(...)` gives -1 for text that isn't a number, so `points < 0 || points > 10` catches it; after adding, the player is in the league even if new, so `find` gives it back to print. `compare` checks the first player for `null`, then the second, and only then compares their totals: the first ahead, the second ahead, or tied."],"tests":[{"name":"Test 1","stdin":"add\nMia\neleven\nadd\nPriya\n9\ncompare\nMia\nPriya\ncompare\nJonas\nPia\nadd\nJonas\n1\ncompare\nMia\nJonas\nleader\nscore\nquit\n","files":{"league.csv":"Mia,8\nPriya,6\nJonas,9\nMia,7\nPriya,9\nJonas,5\n"},"expect":"> Points must be a whole number from 0 to 10\n> Priya, total 24, games [6, 9, 9]\n> Priya is ahead of Mia: 24 to 15\n> No player called Pia\n> Jonas, total 15, games [9, 5, 1]\n> Mia and Jonas are tied at 15\n> Leader: Priya, total 24, games [6, 9, 9]\n> Unknown command: score\n> Good night","hidden":false},{"name":"Test 2","stdin":"leader\ncompare\nMia\nOla\nadd\nMia\n11\nadd\nMia\n-1\nadd\nMia\n0\ncompare\nMia\nMia\ncompare\nOla\nMia\nleader\nquit\n","files":{"league.csv":"Mia\n"},"expect":"> No players yet\n> No player called Mia\n> Points must be a whole number from 0 to 10\n> Points must be a whole number from 0 to 10\n> Mia, total 0, games [0]\n> Mia and Mia are tied at 0\n> No player called Ola\n> Leader: Mia, total 0, games [0]\n> Good night","hidden":true},{"name":"Test 3","stdin":"add\nJonas\n10\ncompare\nJonas\nMia\ncompare\nMia\nJonas\ncompare\njonas\nMia\nadd\nTove\nten\ncompare\nPia\nZed\nLeader\nquit\n","files":{"league.csv":"Mia,8\nJonas,5\nMia,1\n"},"expect":"> Jonas, total 15, games [5, 10]\n> Jonas is ahead of Mia: 15 to 9\n> Jonas is ahead of Mia: 15 to 9\n> No player called jonas\n> Points must be a whole number from 0 to 10\n> No player called Pia\n> Unknown command: Leader\n> Good night","hidden":true}],"require":[],"forbid":[]},{"task":"One last trace through the tools of Java Programming I: a class of your own, a list of objects, `split`, loops inside loops, references and sorting. What does this program print? Look closely at what `tallies` holds.\n","kind":"predict","seed":"import java.util.ArrayList;\nimport java.util.Collections;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Tally> tallies = new ArrayList<>();\n        Tally yes = new Tally(\"yes\");\n        tallies.add(yes);\n        tallies.add(new Tally(\"no\"));\n        tallies.add(yes);\n        String[] votes = \"yes,no,yes,maybe\".split(\",\");\n        for (String vote : votes) {\n            for (Tally tally : tallies) {\n                if (tally.getLabel().equals(vote)) {\n                    tally.add();\n                }\n            }\n        }\n        ArrayList<Integer> counts = new ArrayList<>();\n        for (Tally tally : tallies) {\n            counts.add(tally.getCount());\n        }\n        Collections.sort(counts);\n        System.out.println(tallies.size());\n        System.out.println(yes);\n        System.out.println(counts);\n    }\n}\n// ==== Tally.java ====\npublic class Tally {\n    private String label;\n    private int count;\n\n    public Tally(String label) {\n        this.label = label;\n        this.count = 0;\n    }\n\n    public String getLabel() {\n        return this.label;\n    }\n\n    public int getCount() {\n        return this.count;\n    }\n\n    public void add() {\n        this.count++;\n    }\n\n    public String toString() {\n        return this.label + \": \" + this.count;\n    }\n}\n","solution":"import java.util.ArrayList;\nimport java.util.Collections;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Tally> tallies = new ArrayList<>();\n        Tally yes = new Tally(\"yes\");\n        tallies.add(yes);\n        tallies.add(new Tally(\"no\"));\n        tallies.add(yes);\n        String[] votes = \"yes,no,yes,maybe\".split(\",\");\n        for (String vote : votes) {\n            for (Tally tally : tallies) {\n                if (tally.getLabel().equals(vote)) {\n                    tally.add();\n                }\n            }\n        }\n        ArrayList<Integer> counts = new ArrayList<>();\n        for (Tally tally : tallies) {\n            counts.add(tally.getCount());\n        }\n        Collections.sort(counts);\n        System.out.println(tallies.size());\n        System.out.println(yes);\n        System.out.println(counts);\n    }\n}\n// ==== Tally.java ====\npublic class Tally {\n    private String label;\n    private int count;\n\n    public Tally(String label) {\n        this.label = label;\n        this.count = 0;\n    }\n\n    public String getLabel() {\n        return this.label;\n    }\n\n    public int getCount() {\n        return this.count;\n    }\n\n    public void add() {\n        this.count++;\n    }\n\n    public String toString() {\n        return this.label + \": \" + this.count;\n    }\n}\n","hints":["There are only two Tally objects, but the list holds three references: the `yes` tally is in it twice (module 22). So every `yes` vote finds it twice.","Two `yes` votes, each counted twice, make 4. `maybe` matches nothing. The list of counts gets one number for each of the three references, before it's sorted."],"tests":[{"name":"Output","stdin":"","expect":"3\nyes: 4\n[1, 4, 4]","hidden":false}],"require":[],"forbid":[],"lines":["3","yes: 4","[1, 4, 4]"]}]}