{"id":"objects-with-lists-to-string","slug":"printing-the-owner","title":"Printing an object that holds a list","text":"`System.out.println(shelf)` calls the shelf's toString (module 18). For an object that holds a list, the list belongs in that text too. The shortest way joins the list itself to the text:\n\n```java\npublic String toString() {\n    return this.room + \": \" + this.books;\n}\n```\n\nThe list writes itself out in brackets, with each book's own toString and commas between them: `Hallway: [Emma by Austen, 474 pages, Dracula by Stoker, 418 pages]`. That's hard to read when the books' texts have commas of their own. A loop gives you full control over the text.\n\n### Building the text in a loop\n\nThis toString starts with the room and the number of books, and then adds each book on a line of its own:\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        Bookshelf shelf = new Bookshelf(\"Living room\");\n        shelf.add(new Book(\"Emma\", \"Austen\", 474));\n        shelf.add(new Book(\"Persuasion\", \"Austen\", 249));\n        shelf.add(new Book(\"Dracula\", \"Stoker\", 418));\n        System.out.println(shelf);\n        Bookshelf empty = new Bookshelf(\"Hallway\");\n        System.out.println(empty);\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 String toString() {\n        if (this.books.isEmpty()) {\n            return this.room + \": no books\";\n        }\n        String text = this.room + \": \" + this.books.size() + \" books\";\n        for (Book book : this.books) {\n            text = text + \"\\n\" + book;\n        }\n        return text;\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 toString() {\n        return this.title + \" by \" + this.author + \", \" + this.pages + \" pages\";\n    }\n}\n```\n\n```output\nLiving room: 3 books\nEmma by Austen, 474 pages\nPersuasion by Austen, 249 pages\nDracula by Stoker, 418 pages\nHallway: no books\n```\n\n- You met `\\n` in module 20: inside a String, it's a **line break**. A String can hold several lines, and printing it prints each of them on its own line.\n- `text` starts as the first line, and each round of the loop adds a line break and one book. `+ book` calls the book's own toString.\n- The line break goes *before* each book, not after it, so the text doesn't end with an empty line. `println` adds the last line break itself.\n- An empty shelf gets its own text, checked first with `isEmpty()`. Without that check it would say `Hallway: 0 books`, which is fine too. What an empty object says is part of designing the class.\n\ntoString only builds the text and returns it; it doesn't print anything. The caller decides what to do with it: `System.out.println(shelf)` prints it, and `\"Found: \" + shelf` makes a longer String of it.\n","task":"`Aquarium.java` has a name and a list of fish, and `Fish.java` is ready (its toString gives, for example, `Finn the clownfish`). Write toString for Aquarium. The first line is the aquarium's name and the number of fish, like `Reef tank: 2 fish`, and then each fish comes on a line of its own. There's no line break at the end of the text: `println` adds that. An aquarium with no fish is just `Reef tank: empty`. The check runs:\n\n```java\nAquarium tank = new Aquarium(\"Reef tank\");\nSystem.out.println(tank);\ntank.add(new Fish(\"Finn\", \"clownfish\"));\ntank.add(new Fish(\"Coral\", \"blue tang\"));\nSystem.out.println(tank);\n```\n\nand expects:\n\n```\nReef tank: empty\nReef tank: 2 fish\nFinn the clownfish\nCoral the blue tang\n```\n","kind":"code","seed":"// ==== Aquarium.java ====\nimport java.util.ArrayList;\n\npublic class Aquarium {\n    private String name;\n    private ArrayList<Fish> fish;\n\n    public Aquarium(String name) {\n        this.name = name;\n        this.fish = new ArrayList<>();\n    }\n\n    public void add(Fish newFish) {\n        this.fish.add(newFish);\n    }\n\n    // Write toString here.\n}\n\n// ==== Fish.java ====\npublic class Fish {\n    private String name;\n    private String species;\n\n    public Fish(String name, String species) {\n        this.name = name;\n        this.species = species;\n    }\n\n    public String toString() {\n        return this.name + \" the \" + this.species;\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Aquarium tank = new Aquarium(\"Reef tank\");\n        System.out.println(tank);\n        tank.add(new Fish(\"Finn\", \"clownfish\"));\n        tank.add(new Fish(\"Coral\", \"blue tang\"));\n        System.out.println(tank);\n    }\n}\n","solution":"// ==== Aquarium.java ====\nimport java.util.ArrayList;\n\npublic class Aquarium {\n    private String name;\n    private ArrayList<Fish> fish;\n\n    public Aquarium(String name) {\n        this.name = name;\n        this.fish = new ArrayList<>();\n    }\n\n    public void add(Fish newFish) {\n        this.fish.add(newFish);\n    }\n\n    public String toString() {\n        if (this.fish.isEmpty()) {\n            return this.name + \": empty\";\n        }\n        String text = this.name + \": \" + this.fish.size() + \" fish\";\n        for (Fish one : this.fish) {\n            text = text + \"\\n\" + one;\n        }\n        return text;\n    }\n}\n\n// ==== Fish.java ====\npublic class Fish {\n    private String name;\n    private String species;\n\n    public Fish(String name, String species) {\n        this.name = name;\n        this.species = species;\n    }\n\n    public String toString() {\n        return this.name + \" the \" + this.species;\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Aquarium tank = new Aquarium(\"Reef tank\");\n        System.out.println(tank);\n        tank.add(new Fish(\"Finn\", \"clownfish\"));\n        tank.add(new Fish(\"Coral\", \"blue tang\"));\n        System.out.println(tank);\n    }\n}\n","hints":["Check for the empty aquarium first: `if (this.fish.isEmpty()) { return this.name + \": empty\"; }`.","Then start with the first line, `String text = this.name + \": \" + this.fish.size() + \" fish\";`, add `\"\\n\"` and a fish in each round of a loop over `this.fish`, and return `text` after the loop."],"tests":[{"name":"Test 1","stdin":"","call":"Aquarium tank = new Aquarium(\"Reef tank\");\nSystem.out.println(tank);\ntank.add(new Fish(\"Finn\", \"clownfish\"));\ntank.add(new Fish(\"Coral\", \"blue tang\"));\nSystem.out.println(tank);\n","expect":"Reef tank: empty\nReef tank: 2 fish\nFinn the clownfish\nCoral the blue tang","hidden":false},{"name":"Test 2","stdin":"","call":"Aquarium bowl = new Aquarium(\"Bowl\");\nbowl.add(new Fish(\"Goldie\", \"goldfish\"));\nString text = bowl.toString();\nSystem.out.println(text.length());\nSystem.out.println(text);\n","expect":"32\nBowl: 1 fish\nGoldie the goldfish","hidden":true},{"name":"Test 3","stdin":"","call":"Aquarium pond = new Aquarium(\"Garden pond\");\npond.add(new Fish(\"Koi\", \"carp\"));\npond.add(new Fish(\"Spot\", \"carp\"));\npond.add(new Fish(\"Nib\", \"minnow\"));\nSystem.out.println(\"[\" + pond + \"]\");\n","expect":"[Garden pond: 3 fish\nKoi the carp\nSpot the carp\nNib the minnow]","hidden":true}],"require":[{"pattern":"\\bpublic\\s+String\\s+toString\\s*\\(\\s*\\)","min":2,"message":"Write the method in Aquarium as `public String toString()`."},{"pattern":"\\b(for|while)\\s*\\(","message":"Add the fish to the text in a loop over the list."}],"forbid":[],"more":[{"task":"What does this program print? A necklace's toString joins the colors of its beads with dashes, using an index loop.\n","kind":"predict","seed":"public class Main {\n    public static void main(String[] args) {\n        Necklace a = new Necklace();\n        a.add(\"red\");\n        a.add(\"blue\");\n        a.add(\"red\");\n        Necklace b = new Necklace();\n        System.out.println(a);\n        System.out.println(b);\n        b.add(\"gold\");\n        System.out.println(b);\n        System.out.println(\"Necklace \" + a + \" has \" + a.size() + \" beads\");\n    }\n}\n// ==== Necklace.java ====\nimport java.util.ArrayList;\n\npublic class Necklace {\n    private ArrayList<String> beads;\n\n    public Necklace() {\n        this.beads = new ArrayList<>();\n    }\n\n    public void add(String color) {\n        this.beads.add(color);\n    }\n\n    public int size() {\n        return this.beads.size();\n    }\n\n    public String toString() {\n        String text = \"\";\n        for (int i = 0; i < this.beads.size(); i++) {\n            if (i > 0) {\n                text = text + \"-\";\n            }\n            text = text + this.beads.get(i);\n        }\n        return \"(\" + text + \")\";\n    }\n}\n","solution":"public class Main {\n    public static void main(String[] args) {\n        Necklace a = new Necklace();\n        a.add(\"red\");\n        a.add(\"blue\");\n        a.add(\"red\");\n        Necklace b = new Necklace();\n        System.out.println(a);\n        System.out.println(b);\n        b.add(\"gold\");\n        System.out.println(b);\n        System.out.println(\"Necklace \" + a + \" has \" + a.size() + \" beads\");\n    }\n}\n// ==== Necklace.java ====\nimport java.util.ArrayList;\n\npublic class Necklace {\n    private ArrayList<String> beads;\n\n    public Necklace() {\n        this.beads = new ArrayList<>();\n    }\n\n    public void add(String color) {\n        this.beads.add(color);\n    }\n\n    public int size() {\n        return this.beads.size();\n    }\n\n    public String toString() {\n        String text = \"\";\n        for (int i = 0; i < this.beads.size(); i++) {\n            if (i > 0) {\n                text = text + \"-\";\n            }\n            text = text + this.beads.get(i);\n        }\n        return \"(\" + text + \")\";\n    }\n}\n","hints":["The dash goes in front of every bead except the first one (index 0), so there's no dash at either end. An empty necklace skips the loop, and only the parentheses are left.","Joining `a` to a String with `+` calls its toString, just as `println(a)` does."],"tests":[{"name":"Output","stdin":"","expect":"(red-blue-red)\n()\n(gold)\nNecklace (red-blue-red) has 3 beads","hidden":false}],"require":[],"forbid":[],"lines":["(red-blue-red)","()","(gold)","Necklace (red-blue-red) has 3 beads"]},{"task":"`Bus.java` holds the bus's line number and a list of passenger names. Write its toString: the line number, a colon, and the names in the order they boarded, as you'd write them in a sentence. Commas go between the names, except that the last two are joined with `and`, like `Bus 42: Ada, Ben and Cleo`. With one passenger, it's just `Bus 42: Ada`. The check prints only buses with at least one passenger:\n\n```java\nBus bus = new Bus(42);\nbus.board(\"Ada\");\nSystem.out.println(bus);\nbus.board(\"Ben\");\nSystem.out.println(bus);\nbus.board(\"Cleo\");\nSystem.out.println(bus);\n```\n\nand expects:\n\n```\nBus 42: Ada\nBus 42: Ada and Ben\nBus 42: Ada, Ben and Cleo\n```\n","kind":"code","seed":"// ==== Bus.java ====\nimport java.util.ArrayList;\n\npublic class Bus {\n    private int line;\n    private ArrayList<String> passengers;\n\n    public Bus(int line) {\n        this.line = line;\n        this.passengers = new ArrayList<>();\n    }\n\n    public void board(String name) {\n        this.passengers.add(name);\n    }\n\n    // Write toString here.\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Bus bus = new Bus(42);\n        bus.board(\"Ada\");\n        System.out.println(bus);\n        bus.board(\"Ben\");\n        System.out.println(bus);\n        bus.board(\"Cleo\");\n        System.out.println(bus);\n    }\n}\n","solution":"// ==== Bus.java ====\nimport java.util.ArrayList;\n\npublic class Bus {\n    private int line;\n    private ArrayList<String> passengers;\n\n    public Bus(int line) {\n        this.line = line;\n        this.passengers = new ArrayList<>();\n    }\n\n    public void board(String name) {\n        this.passengers.add(name);\n    }\n\n    public String toString() {\n        String text = \"Bus \" + this.line + \": \";\n        for (int i = 0; i < this.passengers.size(); i++) {\n            if (i > 0 && i == this.passengers.size() - 1) {\n                text = text + \" and \";\n            } else if (i > 0) {\n                text = text + \", \";\n            }\n            text = text + this.passengers.get(i);\n        }\n        return text;\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Bus bus = new Bus(42);\n        bus.board(\"Ada\");\n        System.out.println(bus);\n        bus.board(\"Ben\");\n        System.out.println(bus);\n        bus.board(\"Cleo\");\n        System.out.println(bus);\n    }\n}\n","hints":["Loop over the indexes, as the necklace does, so that you know where each name is. The first name gets nothing in front of it, the last one (when it isn't also the first) gets `and` with a space on each side, and every other one gets a comma and a space.","In `for (int i = 0; i < this.passengers.size(); i++)`: `if (i > 0 && i == this.passengers.size() - 1)` adds `\" and \"`, `else if (i > 0)` adds `\", \"`, and then the name `this.passengers.get(i)` is added."],"tests":[{"name":"Test 1","stdin":"","call":"Bus bus = new Bus(42);\nbus.board(\"Ada\");\nSystem.out.println(bus);\nbus.board(\"Ben\");\nSystem.out.println(bus);\nbus.board(\"Cleo\");\nSystem.out.println(bus);\n","expect":"Bus 42: Ada\nBus 42: Ada and Ben\nBus 42: Ada, Ben and Cleo","hidden":false},{"name":"Test 2","stdin":"","call":"Bus night = new Bus(7);\nfor (int i = 1; i <= 5; i++) {\n    night.board(\"P\" + i);\n}\nSystem.out.println(night);\n","expect":"Bus 7: P1, P2, P3, P4 and P5","hidden":true},{"name":"Test 3","stdin":"","call":"Bus a = new Bus(1);\nBus b = new Bus(2);\na.board(\"Zoe\");\nb.board(\"Yan\");\nb.board(\"Xia\");\nb.board(\"Yan\");\nSystem.out.println(a + \" / \" + b);\n","expect":"Bus 1: Zoe / Bus 2: Yan, Xia and Yan","hidden":true}],"require":[{"pattern":"\\bpublic\\s+String\\s+toString\\s*\\(\\s*\\)","message":"Write the method as `public String toString()`."}],"forbid":[]}]}