{"id":"interfaces-return-and-lists","slug":"return-and-lists","title":"Lists of an interface, and interfaces as return types","text":"A phone's media player plays voice memos and radio shows. From every item in its queue, it needs a title, a length in seconds, and a way to play it:\n\n```java\npublic interface Playable {\n    String title();\n    int seconds();\n    void play();\n}\n```\n\n### A list of Playables\n\nA list's element type can be an interface too. Then the list holds objects of any class that implements it:\n\n```java\nimport java.util.ArrayList;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Playable> queue = new ArrayList<>();\n        queue.add(new VoiceMemo(\"Groceries\", 45));\n        queue.add(new RadioShow(\"Morning News\", 5));\n        queue.add(new VoiceMemo(\"Door code\", 12));\n\n        int total = 0;\n        for (Playable item : queue) {\n            item.play();\n            total += item.seconds();\n        }\n        System.out.println(\"In the queue: \" + total + \" seconds\");\n\n        Playable longest = longest(queue);\n        System.out.println(\"Longest: \" + longest.title());\n    }\n\n    public static Playable longest(ArrayList<Playable> queue) {\n        Playable longest = queue.get(0);\n        for (Playable item : queue) {\n            if (item.seconds() > longest.seconds()) {\n                longest = item;\n            }\n        }\n        return longest;\n    }\n}\n// ==== Playable.java ====\npublic interface Playable {\n    String title();\n    int seconds();\n    void play();\n}\n// ==== VoiceMemo.java ====\npublic class VoiceMemo implements Playable {\n    private String title;\n    private int seconds;\n\n    public VoiceMemo(String title, int seconds) {\n        this.title = title;\n        this.seconds = seconds;\n    }\n\n    @Override\n    public String title() {\n        return this.title;\n    }\n\n    @Override\n    public int seconds() {\n        return this.seconds;\n    }\n\n    @Override\n    public void play() {\n        System.out.println(\"Memo: \" + this.title);\n    }\n}\n// ==== RadioShow.java ====\npublic class RadioShow implements Playable {\n    private String name;\n    private int minutes;\n\n    public RadioShow(String name, int minutes) {\n        this.name = name;\n        this.minutes = minutes;\n    }\n\n    @Override\n    public String title() {\n        return this.name;\n    }\n\n    @Override\n    public int seconds() {\n        return 60 * this.minutes;\n    }\n\n    @Override\n    public void play() {\n        System.out.println(\"On air: \" + this.name);\n    }\n}\n```\n\n```output\nMemo: Groceries\nOn air: Morning News\nMemo: Door code\nIn the queue: 357 seconds\nLongest: Morning News\n```\n\n- `ArrayList<Playable>` holds memos and shows side by side. `add` accepts a VoiceMemo because a VoiceMemo is a Playable.\n- The loop variable `item` has the type Playable. Each time round, it refers to one object, and that object's `play` runs: a memo's prints `Memo:`, a show's prints `On air:`. The loop doesn't know or care which kind each item is.\n- A new kind of item, such as a chapter of an audiobook, would be one more class that implements Playable. The loop wouldn't change.\n- The class names VoiceMemo and RadioShow appear only where the objects are made. Everything after that works with Playable.\n\n### Returning a Playable\n\n`longest` has the return type Playable. It returns whichever object in the queue has the most seconds, and the caller keeps it in a Playable variable, so the caller may use Playable's methods on it.\n\n- The object that comes back is still what it was: the radio show. `longest(queue).play()` would print `On air: Morning News`.\n- A method can also create an object and return it as a Playable. The caller then doesn't even need to know which class it got. The last challenge of this step does that.\n","task":"Write the method `find(ArrayList<Playable> queue, String title)`, which returns the item in the queue with that title, or `null` if there's none. If several items have the title, return the first of them. `Playable.java`, `VoiceMemo.java` and `RadioShow.java` are ready. The check runs:\n\n```java\nArrayList<Playable> queue = new ArrayList<>();\nqueue.add(new VoiceMemo(\"Groceries\", 45));\nqueue.add(new RadioShow(\"Morning News\", 5));\nPlayable found = find(queue, \"Morning News\");\nfound.play();\nSystem.out.println(found.seconds());\nSystem.out.println(find(queue, \"Weather\") == null);\n```\n\nand expects:\n\n```\nOn air: Morning News\n300\ntrue\n```\n","kind":"code","seed":"// ==== Main.java ====\nimport java.util.ArrayList;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Playable> queue = new ArrayList<>();\n        queue.add(new VoiceMemo(\"Groceries\", 45));\n        queue.add(new RadioShow(\"Morning News\", 5));\n        Playable found = find(queue, \"Morning News\");\n        found.play();\n        System.out.println(found.seconds());\n        System.out.println(find(queue, \"Weather\") == null);\n    }\n\n    // Write the method find here.\n}\n\n// ==== Playable.java ====\npublic interface Playable {\n    String title();\n    int seconds();\n    void play();\n}\n\n// ==== VoiceMemo.java ====\npublic class VoiceMemo implements Playable {\n    private String title;\n    private int seconds;\n\n    public VoiceMemo(String title, int seconds) {\n        this.title = title;\n        this.seconds = seconds;\n    }\n\n    @Override\n    public String title() {\n        return this.title;\n    }\n\n    @Override\n    public int seconds() {\n        return this.seconds;\n    }\n\n    @Override\n    public void play() {\n        System.out.println(\"Memo: \" + this.title);\n    }\n}\n\n// ==== RadioShow.java ====\npublic class RadioShow implements Playable {\n    private String name;\n    private int minutes;\n\n    public RadioShow(String name, int minutes) {\n        this.name = name;\n        this.minutes = minutes;\n    }\n\n    @Override\n    public String title() {\n        return this.name;\n    }\n\n    @Override\n    public int seconds() {\n        return 60 * this.minutes;\n    }\n\n    @Override\n    public void play() {\n        System.out.println(\"On air: \" + this.name);\n    }\n}\n","solution":"// ==== Main.java ====\nimport java.util.ArrayList;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Playable> queue = new ArrayList<>();\n        queue.add(new VoiceMemo(\"Groceries\", 45));\n        queue.add(new RadioShow(\"Morning News\", 5));\n        Playable found = find(queue, \"Morning News\");\n        found.play();\n        System.out.println(found.seconds());\n        System.out.println(find(queue, \"Weather\") == null);\n    }\n\n    public static Playable find(ArrayList<Playable> queue, String title) {\n        for (Playable item : queue) {\n            if (item.title().equals(title)) {\n                return item;\n            }\n        }\n        return null;\n    }\n}\n\n// ==== Playable.java ====\npublic interface Playable {\n    String title();\n    int seconds();\n    void play();\n}\n\n// ==== VoiceMemo.java ====\npublic class VoiceMemo implements Playable {\n    private String title;\n    private int seconds;\n\n    public VoiceMemo(String title, int seconds) {\n        this.title = title;\n        this.seconds = seconds;\n    }\n\n    @Override\n    public String title() {\n        return this.title;\n    }\n\n    @Override\n    public int seconds() {\n        return this.seconds;\n    }\n\n    @Override\n    public void play() {\n        System.out.println(\"Memo: \" + this.title);\n    }\n}\n\n// ==== RadioShow.java ====\npublic class RadioShow implements Playable {\n    private String name;\n    private int minutes;\n\n    public RadioShow(String name, int minutes) {\n        this.name = name;\n        this.minutes = minutes;\n    }\n\n    @Override\n    public String title() {\n        return this.name;\n    }\n\n    @Override\n    public int seconds() {\n        return 60 * this.minutes;\n    }\n\n    @Override\n    public void play() {\n        System.out.println(\"On air: \" + this.name);\n    }\n}\n","hints":["The header is `public static Playable find(ArrayList<Playable> queue, String title)`. Go through the queue with a for-each loop, and compare each item's `title()` with `equals`.","Return the item as soon as its title matches: that makes the first match win. After the loop, nothing matched, so `return null;`."],"tests":[{"name":"Test 1","stdin":"","call":"ArrayList<Playable> queue = new ArrayList<>();\nqueue.add(new VoiceMemo(\"Groceries\", 45));\nqueue.add(new RadioShow(\"Morning News\", 5));\nPlayable found = find(queue, \"Morning News\");\nfound.play();\nSystem.out.println(found.seconds());\nSystem.out.println(find(queue, \"Weather\") == null);\n","expect":"On air: Morning News\n300\ntrue","hidden":false},{"name":"Test 2","stdin":"","call":"ArrayList<Playable> queue = new ArrayList<>();\nSystem.out.println(find(queue, \"News\") == null);\nqueue.add(new RadioShow(\"Jazz Hour\", 1));\nqueue.add(new VoiceMemo(\"News\", 10));\nqueue.add(new RadioShow(\"News\", 2));\nSystem.out.println(find(queue, \"News\").seconds());\nString start = \"Jazz\";\nfind(queue, start + \" Hour\").play();\n","expect":"true\n10\nOn air: Jazz Hour","hidden":true},{"name":"Test 3","stdin":"","call":"ArrayList<Playable> queue = new ArrayList<>();\nqueue.add(new VoiceMemo(\"Door code\", 12));\nSystem.out.println(find(queue, \"door code\") == null);\nSystem.out.println(find(queue, \"Door code\") == queue.get(0));\n","expect":"true\ntrue","hidden":true}],"require":[{"pattern":"\\bpublic\\s+static\\s+Playable\\s+find\\s*\\(\\s*ArrayList<Playable>\\s+\\w+\\s*,\\s*String\\s+\\w+\\s*\\)","message":"Write the method as `public static Playable find(ArrayList<Playable> queue, String title)`."}],"forbid":[],"more":[{"task":"The player plays only the long items in the queue: those of at least two minutes. What does this program print?\n","kind":"predict","seed":"import java.util.ArrayList;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Playable> queue = new ArrayList<>();\n        queue.add(new RadioShow(\"Jazz Hour\", 2));\n        queue.add(new VoiceMemo(\"Parking spot\", 30));\n        queue.add(new VoiceMemo(\"Birthday song\", 150));\n        int count = 0;\n        for (Playable item : queue) {\n            if (item.seconds() >= 120) {\n                item.play();\n                count++;\n            }\n        }\n        Playable last = queue.get(queue.size() - 1);\n        System.out.println(count + \" \" + last.title());\n    }\n}\n// ==== Playable.java ====\npublic interface Playable {\n    String title();\n    int seconds();\n    void play();\n}\n// ==== VoiceMemo.java ====\npublic class VoiceMemo implements Playable {\n    private String title;\n    private int seconds;\n\n    public VoiceMemo(String title, int seconds) {\n        this.title = title;\n        this.seconds = seconds;\n    }\n\n    @Override\n    public String title() {\n        return this.title;\n    }\n\n    @Override\n    public int seconds() {\n        return this.seconds;\n    }\n\n    @Override\n    public void play() {\n        System.out.println(\"Memo: \" + this.title);\n    }\n}\n// ==== RadioShow.java ====\npublic class RadioShow implements Playable {\n    private String name;\n    private int minutes;\n\n    public RadioShow(String name, int minutes) {\n        this.name = name;\n        this.minutes = minutes;\n    }\n\n    @Override\n    public String title() {\n        return this.name;\n    }\n\n    @Override\n    public int seconds() {\n        return 60 * this.minutes;\n    }\n\n    @Override\n    public void play() {\n        System.out.println(\"On air: \" + this.name);\n    }\n}\n","solution":"import java.util.ArrayList;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Playable> queue = new ArrayList<>();\n        queue.add(new RadioShow(\"Jazz Hour\", 2));\n        queue.add(new VoiceMemo(\"Parking spot\", 30));\n        queue.add(new VoiceMemo(\"Birthday song\", 150));\n        int count = 0;\n        for (Playable item : queue) {\n            if (item.seconds() >= 120) {\n                item.play();\n                count++;\n            }\n        }\n        Playable last = queue.get(queue.size() - 1);\n        System.out.println(count + \" \" + last.title());\n    }\n}\n// ==== Playable.java ====\npublic interface Playable {\n    String title();\n    int seconds();\n    void play();\n}\n// ==== VoiceMemo.java ====\npublic class VoiceMemo implements Playable {\n    private String title;\n    private int seconds;\n\n    public VoiceMemo(String title, int seconds) {\n        this.title = title;\n        this.seconds = seconds;\n    }\n\n    @Override\n    public String title() {\n        return this.title;\n    }\n\n    @Override\n    public int seconds() {\n        return this.seconds;\n    }\n\n    @Override\n    public void play() {\n        System.out.println(\"Memo: \" + this.title);\n    }\n}\n// ==== RadioShow.java ====\npublic class RadioShow implements Playable {\n    private String name;\n    private int minutes;\n\n    public RadioShow(String name, int minutes) {\n        this.name = name;\n        this.minutes = minutes;\n    }\n\n    @Override\n    public String title() {\n        return this.name;\n    }\n\n    @Override\n    public int seconds() {\n        return 60 * this.minutes;\n    }\n\n    @Override\n    public void play() {\n        System.out.println(\"On air: \" + this.name);\n    }\n}\n","hints":["A radio show's length is given in minutes, but `seconds()` returns seconds: the Jazz Hour of 2 minutes is 120 seconds, just enough.","Each item that's long enough runs its own `play`: a show prints `On air:`, a memo prints `Memo:`. The last item in the list is the birthday song."],"tests":[{"name":"Output","stdin":"","expect":"On air: Jazz Hour\nMemo: Birthday song\n2 Birthday song","hidden":false}],"require":[],"forbid":[],"lines":["On air: Jazz Hour","Memo: Birthday song","2 Birthday song"]},{"task":"The player reads its queue from lines of text such as `memo,Groceries,45` or `show,Morning News,5`: the kind, the title, and the length, in seconds for a memo and in minutes for a show. Write the method `fromLine(String line)`, which makes a new VoiceMemo or a new RadioShow from the line and returns it. Its return type is Playable, so the caller doesn't need to know which class it gets. The kind is always `memo` or `show`. The check runs:\n\n```java\nPlayable first = fromLine(\"memo,Groceries,45\");\nPlayable second = fromLine(\"show,Morning News,5\");\nfirst.play();\nsecond.play();\nSystem.out.println(first.seconds() + second.seconds());\n```\n\nand expects:\n\n```\nMemo: Groceries\nOn air: Morning News\n345\n```\n","kind":"code","seed":"// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Playable first = fromLine(\"memo,Groceries,45\");\n        Playable second = fromLine(\"show,Morning News,5\");\n        first.play();\n        second.play();\n        System.out.println(first.seconds() + second.seconds());\n    }\n\n    // Write the method fromLine here.\n}\n\n// ==== Playable.java ====\npublic interface Playable {\n    String title();\n    int seconds();\n    void play();\n}\n\n// ==== VoiceMemo.java ====\npublic class VoiceMemo implements Playable {\n    private String title;\n    private int seconds;\n\n    public VoiceMemo(String title, int seconds) {\n        this.title = title;\n        this.seconds = seconds;\n    }\n\n    @Override\n    public String title() {\n        return this.title;\n    }\n\n    @Override\n    public int seconds() {\n        return this.seconds;\n    }\n\n    @Override\n    public void play() {\n        System.out.println(\"Memo: \" + this.title);\n    }\n}\n\n// ==== RadioShow.java ====\npublic class RadioShow implements Playable {\n    private String name;\n    private int minutes;\n\n    public RadioShow(String name, int minutes) {\n        this.name = name;\n        this.minutes = minutes;\n    }\n\n    @Override\n    public String title() {\n        return this.name;\n    }\n\n    @Override\n    public int seconds() {\n        return 60 * this.minutes;\n    }\n\n    @Override\n    public void play() {\n        System.out.println(\"On air: \" + this.name);\n    }\n}\n","solution":"// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Playable first = fromLine(\"memo,Groceries,45\");\n        Playable second = fromLine(\"show,Morning News,5\");\n        first.play();\n        second.play();\n        System.out.println(first.seconds() + second.seconds());\n    }\n\n    public static Playable fromLine(String line) {\n        String[] parts = line.split(\",\");\n        int length = Integer.valueOf(parts[2]);\n        if (parts[0].equals(\"memo\")) {\n            return new VoiceMemo(parts[1], length);\n        }\n        return new RadioShow(parts[1], length);\n    }\n}\n\n// ==== Playable.java ====\npublic interface Playable {\n    String title();\n    int seconds();\n    void play();\n}\n\n// ==== VoiceMemo.java ====\npublic class VoiceMemo implements Playable {\n    private String title;\n    private int seconds;\n\n    public VoiceMemo(String title, int seconds) {\n        this.title = title;\n        this.seconds = seconds;\n    }\n\n    @Override\n    public String title() {\n        return this.title;\n    }\n\n    @Override\n    public int seconds() {\n        return this.seconds;\n    }\n\n    @Override\n    public void play() {\n        System.out.println(\"Memo: \" + this.title);\n    }\n}\n\n// ==== RadioShow.java ====\npublic class RadioShow implements Playable {\n    private String name;\n    private int minutes;\n\n    public RadioShow(String name, int minutes) {\n        this.name = name;\n        this.minutes = minutes;\n    }\n\n    @Override\n    public String title() {\n        return this.name;\n    }\n\n    @Override\n    public int seconds() {\n        return 60 * this.minutes;\n    }\n\n    @Override\n    public void play() {\n        System.out.println(\"On air: \" + this.name);\n    }\n}\n","hints":["The header is `public static Playable fromLine(String line)`. `line.split(\",\")` gives the three parts, and `Integer.valueOf(parts[2])` turns the length into an int.","If `parts[0]` equals `memo`, return `new VoiceMemo(parts[1], length)`; otherwise return `new RadioShow(parts[1], length)`. Both fit the return type Playable."],"tests":[{"name":"Test 1","stdin":"","call":"Playable first = fromLine(\"memo,Groceries,45\");\nPlayable second = fromLine(\"show,Morning News,5\");\nfirst.play();\nsecond.play();\nSystem.out.println(first.seconds() + second.seconds());\n","expect":"Memo: Groceries\nOn air: Morning News\n345","hidden":false},{"name":"Test 2","stdin":"","call":"String[] lines = {\"show,Jazz Hour,60\", \"memo,Door code,12\", \"memo,Parking spot,30\"};\nArrayList<Playable> queue = new ArrayList<>();\nfor (String line : lines) {\n    queue.add(fromLine(line));\n}\nint total = 0;\nfor (Playable item : queue) {\n    total += item.seconds();\n}\nSystem.out.println(queue.size() + \" \" + total + \" \" + queue.get(2).title());\n","expect":"3 3642 Parking spot","hidden":true},{"name":"Test 3","stdin":"","call":"System.out.println(fromLine(\"show,Memo Hour,2\").getClass().getName());\nSystem.out.println(fromLine(\"memo,Show times,2\").getClass().getName());\nSystem.out.println(fromLine(\"memo,Show times,2\").seconds());\n","expect":"RadioShow\nVoiceMemo\n2","hidden":true}],"require":[{"pattern":"\\bpublic\\s+static\\s+Playable\\s+fromLine\\s*\\(\\s*String\\s+\\w+\\s*\\)","message":"Write the method as `public static Playable fromLine(String line)`."}],"forbid":[]}]}