{"id":"interfaces-list","slug":"list-interface","title":"Java's List interface","text":"Since module 13, every list in this course has been an `ArrayList`. ArrayList is a class, and it implements an interface from `java.util` called **List**. List promises the methods that every list has: `add`, `get`, `set`, `remove`, `size`, `contains`, `indexOf`, `isEmpty`, `clear` and the rest of module 14's toolbox. ArrayList is one class that keeps that promise.\n\nSo a list variable can have the interface as its type:\n\n```java\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class Main {\n    public static void main(String[] args) {\n        List<String> stops = new ArrayList<>();\n        stops.add(\"Harbor\");\n        stops.add(\"Market Square\");\n        stops.add(\"Museum\");\n        stops.add(1, \"Old Mill\");\n        System.out.println(stops);\n        System.out.println(stops.size() + \" stops, the last is \" + stops.get(stops.size() - 1));\n        printTimetable(stops, 4);\n    }\n\n    public static void printTimetable(List<String> stops, int minutesBetween) {\n        int minute = 0;\n        for (String stop : stops) {\n            System.out.println(minute + \" min: \" + stop);\n            minute += minutesBetween;\n        }\n    }\n}\n```\n\n```output\n[Harbor, Old Mill, Market Square, Museum]\n4 stops, the last is Museum\n0 min: Harbor\n4 min: Old Mill\n8 min: Market Square\n12 min: Museum\n```\n\n- `List<String> stops = new ArrayList<>();`: the variable's type is the interface, and the object is an ArrayList. List needs its own import, `import java.util.List;`.\n- Every call works as before, since every one of those methods is in List. The list prints as before too: `println` runs the object's `toString`, and the object is an ArrayList.\n- `printTimetable` takes a `List<String>`, so it accepts any list of Strings: an ArrayList, or an object of any other class that implements List. Java has others, such as `LinkedList`, which keeps its values in a different way. This course keeps to ArrayList, but code written for List works with any of them.\n- `new List<>()` doesn't compile, as with any interface.\n\n### Why many programs write List\n\nMany Java programs declare their lists as `List<String> names = new ArrayList<>();`. It's step 3's advice: the rest of the code uses only what List promises, so it doesn't depend on which kind of list it has. A method with a List parameter accepts more kinds of lists, and a program could change `new ArrayList<>()` to another kind of list in one place.\n\nThe same idea is behind `Collections.sort`, which you've used since module 28: its parameter is a List, and that's why it can sort an ArrayList.\n\n### An ArrayList fits a List, not the other way round\n\nAn ArrayList can go wherever a List is asked for. But a List variable can't be given to a method that asks for an ArrayList: javac knows only that the variable holds some list, not which kind.\n\n```java\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class Main {\n    public static void main(String[] args) {\n        List<String> stops = new ArrayList<>();\n        stops.add(\"Harbor\");\n        System.out.println(count(stops));\n    }\n\n    public static int count(ArrayList<String> stops) {\n        return stops.size();\n    }\n}\n```\n\n```javac\nMain.java:8: error: incompatible types: List<String> cannot be converted to ArrayList<String>\n        System.out.println(count(stops));\n                                 ^\nNote: Some messages have been simplified; recompile with -Xdiags:verbose to get full output\n1 error\n```\n\nSo `List<String>` is usually the better parameter type: it accepts a List variable and an ArrayList variable alike. The rest of this module writes List for its parameters.\n","task":"The tram's display shows the route on one line, with ` > ` between the stops. Write the method `routeText(List<String> stops)`, which returns that text. There's no ` > ` before the first stop or after the last one, and an empty list gives an empty String. The check runs:\n\n```java\nList<String> stops = new ArrayList<>();\nstops.add(\"Harbor\");\nstops.add(\"Old Mill\");\nstops.add(\"Museum\");\nSystem.out.println(routeText(stops));\n```\n\nand expects:\n\n```\nHarbor > Old Mill > Museum\n```\n","kind":"code","seed":"import java.util.ArrayList;\nimport java.util.List;\n\npublic class Main {\n    public static void main(String[] args) {\n        List<String> stops = new ArrayList<>();\n        stops.add(\"Harbor\");\n        stops.add(\"Old Mill\");\n        stops.add(\"Museum\");\n        System.out.println(routeText(stops));\n    }\n\n    // Write the method routeText here.\n}\n","solution":"import java.util.ArrayList;\nimport java.util.List;\n\npublic class Main {\n    public static void main(String[] args) {\n        List<String> stops = new ArrayList<>();\n        stops.add(\"Harbor\");\n        stops.add(\"Old Mill\");\n        stops.add(\"Museum\");\n        System.out.println(routeText(stops));\n    }\n\n    public static String routeText(List<String> stops) {\n        String text = \"\";\n        for (int i = 0; i < stops.size(); i++) {\n            if (i > 0) {\n                text += \" > \";\n            }\n            text += stops.get(i);\n        }\n        return text;\n    }\n}\n","hints":["The header is `public static String routeText(List<String> stops)`. Inside, `stops` has every list method you know: `size()`, `get(i)`, and a for-each loop works too.","Build the text in a String variable. Before every stop except the first (index 0), add ` > `, then add the stop."],"tests":[{"name":"Test 1","stdin":"","call":"List<String> stops = new ArrayList<>();\nstops.add(\"Harbor\");\nstops.add(\"Old Mill\");\nstops.add(\"Museum\");\nSystem.out.println(routeText(stops));\n","expect":"Harbor > Old Mill > Museum","hidden":false},{"name":"Test 2","stdin":"","call":"ArrayList<String> one = new ArrayList<>();\none.add(\"Depot\");\nSystem.out.println(\"[\" + routeText(one) + \"]\");\nList<String> none = new ArrayList<>();\nSystem.out.println(\"[\" + routeText(none) + \"]\");\n","expect":"[Depot]\n[]","hidden":true},{"name":"Test 3","stdin":"","call":"List<String> stops = new ArrayList<>();\nstops.add(\"A\");\nstops.add(\"B\");\nSystem.out.println(routeText(stops));\nstops.add(\"A\");\nSystem.out.println(routeText(stops) + \" \" + stops.size());\n","expect":"A > B\nA > B > A 3","hidden":true}],"require":[{"pattern":"\\bpublic\\s+static\\s+String\\s+routeText\\s*\\(\\s*List<String>\\s+\\w+\\s*\\)","message":"Write the method as `public static String routeText(List<String> stops)`."}],"forbid":[],"more":[{"task":"What does this program print?\n","kind":"predict","seed":"import java.util.ArrayList;\nimport java.util.List;\n\npublic class Main {\n    public static void main(String[] args) {\n        List<String> line = new ArrayList<>();\n        line.add(\"Harbor\");\n        line.add(\"Mill\");\n        line.add(\"Museum\");\n        line.add(\"Mill\");\n        line.remove(\"Mill\");\n        System.out.println(line);\n        System.out.println(line.indexOf(\"Mill\") + \" \" + line.size());\n        addDepot(line);\n        System.out.println(line.get(0) + \" \" + line.contains(\"Depot\"));\n    }\n\n    public static void addDepot(List<String> stops) {\n        stops.add(0, \"Depot\");\n    }\n}\n","solution":"import java.util.ArrayList;\nimport java.util.List;\n\npublic class Main {\n    public static void main(String[] args) {\n        List<String> line = new ArrayList<>();\n        line.add(\"Harbor\");\n        line.add(\"Mill\");\n        line.add(\"Museum\");\n        line.add(\"Mill\");\n        line.remove(\"Mill\");\n        System.out.println(line);\n        System.out.println(line.indexOf(\"Mill\") + \" \" + line.size());\n        addDepot(line);\n        System.out.println(line.get(0) + \" \" + line.contains(\"Depot\"));\n    }\n\n    public static void addDepot(List<String> stops) {\n        stops.add(0, \"Depot\");\n    }\n}\n","hints":["`remove(value)` takes out only the first copy of the value, so the second Mill stays, at the end.","`addDepot` gets the same list object, not a copy (module 14), so the Depot it puts at index 0 is in `line` too."],"tests":[{"name":"Output","stdin":"","expect":"[Harbor, Museum, Mill]\n2 3\nDepot true","hidden":false}],"require":[],"forbid":[],"lines":["[Harbor, Museum, Mill]","2 3","Depot true"]},{"task":"For the return trip, write the method `reversed(List<String> stops)`, which returns a new list with the same stops in the opposite order. Its return type is `List<String>`. The list it gets must stay as it was. The check runs:\n\n```java\nList<String> there = new ArrayList<>();\nthere.add(\"Harbor\");\nthere.add(\"Old Mill\");\nthere.add(\"Museum\");\nList<String> back = reversed(there);\nSystem.out.println(back);\nSystem.out.println(there);\n```\n\nand expects:\n\n```\n[Museum, Old Mill, Harbor]\n[Harbor, Old Mill, Museum]\n```\n","kind":"code","seed":"import java.util.ArrayList;\nimport java.util.List;\n\npublic class Main {\n    public static void main(String[] args) {\n        List<String> there = new ArrayList<>();\n        there.add(\"Harbor\");\n        there.add(\"Old Mill\");\n        there.add(\"Museum\");\n        List<String> back = reversed(there);\n        System.out.println(back);\n        System.out.println(there);\n    }\n\n    // Write the method reversed here.\n}\n","solution":"import java.util.ArrayList;\nimport java.util.List;\n\npublic class Main {\n    public static void main(String[] args) {\n        List<String> there = new ArrayList<>();\n        there.add(\"Harbor\");\n        there.add(\"Old Mill\");\n        there.add(\"Museum\");\n        List<String> back = reversed(there);\n        System.out.println(back);\n        System.out.println(there);\n    }\n\n    public static List<String> reversed(List<String> stops) {\n        List<String> result = new ArrayList<>();\n        for (int i = stops.size() - 1; i >= 0; i--) {\n            result.add(stops.get(i));\n        }\n        return result;\n    }\n}\n","hints":["The header is `public static List<String> reversed(List<String> stops)`. Make a new list inside, `List<String> result = new ArrayList<>();`, and return it at the end.","Go through `stops` from the last index, `stops.size() - 1`, down to 0, and add each stop to `result`. Don't change `stops` itself."],"tests":[{"name":"Test 1","stdin":"","call":"List<String> there = new ArrayList<>();\nthere.add(\"Harbor\");\nthere.add(\"Old Mill\");\nthere.add(\"Museum\");\nList<String> back = reversed(there);\nSystem.out.println(back);\nSystem.out.println(there);\n","expect":"[Museum, Old Mill, Harbor]\n[Harbor, Old Mill, Museum]","hidden":false},{"name":"Test 2","stdin":"","call":"List<String> none = new ArrayList<>();\nSystem.out.println(reversed(none));\nArrayList<String> one = new ArrayList<>();\none.add(\"Depot\");\nSystem.out.println(reversed(one));\n","expect":"[]\n[Depot]","hidden":true},{"name":"Test 3","stdin":"","call":"List<String> there = new ArrayList<>();\nthere.add(\"A\");\nthere.add(\"B\");\nthere.add(\"A\");\nthere.add(\"C\");\nList<String> back = reversed(there);\nback.add(\"Z\");\nSystem.out.println(back + \" \" + there);\n","expect":"[C, A, B, A, Z] [A, B, A, C]","hidden":true}],"require":[{"pattern":"\\bpublic\\s+static\\s+List<String>\\s+reversed\\s*\\(\\s*List<String>\\s+\\w+\\s*\\)","message":"Write the method as `public static List<String> reversed(List<String> stops)`."}],"forbid":[]}]}