{"id":"object-interaction-lists","slug":"equals-and-lists","title":"equals and lists","text":"The list methods `contains`, `indexOf` and `remove(value)` from module 14 all search the list. To decide whether a value in the list is the one they're looking for, they call `equals`. With Strings that has always worked, because String has an `equals` of its own that compares the letters. With objects of your own class, it works as soon as the class has its own `equals`, like the Seat from the previous step:\n\n```java\nimport java.util.ArrayList;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Seat> booked = new ArrayList<>();\n        booked.add(new Seat(\"A\", 3));\n        booked.add(new Seat(\"B\", 7));\n        booked.add(new Seat(\"C\", 1));\n\n        System.out.println(booked.contains(new Seat(\"B\", 7)));\n        System.out.println(booked.indexOf(new Seat(\"C\", 1)));\n        booked.remove(new Seat(\"A\", 3));\n        System.out.println(booked);\n    }\n}\n// ==== Seat.java ====\npublic class Seat {\n    private String row;\n    private int number;\n\n    public Seat(String row, int number) {\n        this.row = row;\n        this.number = number;\n    }\n\n    public boolean equals(Object compared) {\n        if (this == compared) {\n            return true;\n        }\n        if (!(compared instanceof Seat)) {\n            return false;\n        }\n        Seat other = (Seat) compared;\n        return this.row.equals(other.row) && this.number == other.number;\n    }\n\n    public String toString() {\n        return this.row + this.number;\n    }\n}\n```\n\n```output\ntrue\n2\n[B7, C1]\n```\n\n- Each `new Seat(...)` in the parentheses is a brand-new object, not one of the objects in the list. `contains` finds it anyway, because it compares with `equals`, and a seat in the list is equal to it.\n- `indexOf` gives the index of the first equal seat, and `remove(value)` removes the first equal seat, as they did with Strings.\n- Printing a list prints each value with its `toString`, between brackets and separated by commas.\n\nWithout the `equals` method in Seat, all three would miss: `contains` would print `false`, `indexOf` would print `-1`, and `remove` wouldn't remove anything. The seat they're given is never the very same object as one in the list, and the `equals` that every class gets only looks for the same object.\n\nFor lists, `equals` is all it takes. Some of Java's other collections, which come in part 8, also need a second method, `hashCode`.\n\n### Only once in the list\n\nA common use is a list that holds each value only once: before adding, check that no equal value is in it yet.\n\n```java\nSeat seat = new Seat(row, number);\nif (booked.contains(seat)) {\n    System.out.println(seat + \" is already taken\");\n} else {\n    booked.add(seat);\n    System.out.println(\"Booked \" + seat);\n}\n```\n","task":"At a bakery, the orders waiting to be picked up are in a list, in the order they were placed. `Main.java` is ready: it reads pick-ups such as `Ben bagel` (a customer and an item) until an empty line. For each one, it looks for the order's place in line with `indexOf`, prints it, and takes the order out of the list with `remove`. But no order is ever found, because `Order` has no `equals` of its own. Write `equals` in `Order.java`: two orders are equal when they're for the same customer and the same item. For the input shown below, the program prints:\n\n```\nPicked up: bagel for Ben, number 2 in line\nNo order: muffin for Ada\nPicked up: bagel for Di, number 3 in line\nStill waiting: [croissant for Ada, muffin for Cy]\n```\n","kind":"code","seed":"// ==== Order.java ====\npublic class Order {\n    private String customer;\n    private String item;\n\n    public Order(String customer, String item) {\n        this.customer = customer;\n        this.item = item;\n    }\n\n    // Write the equals method here.\n\n    public String toString() {\n        return this.item + \" for \" + this.customer;\n    }\n}\n\n// ==== Main.java ====\nimport java.util.ArrayList;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Order> waiting = new ArrayList<>();\n        waiting.add(new Order(\"Ada\", \"croissant\"));\n        waiting.add(new Order(\"Ben\", \"bagel\"));\n        waiting.add(new Order(\"Cy\", \"muffin\"));\n        waiting.add(new Order(\"Di\", \"bagel\"));\n\n        Scanner scanner = new Scanner(System.in);\n        while (true) {\n            String line = scanner.nextLine();\n            if (line.isEmpty()) {\n                break;\n            }\n            String[] parts = line.split(\" \");\n            Order order = new Order(parts[0], parts[1]);\n            int place = waiting.indexOf(order);\n            if (place == -1) {\n                System.out.println(\"No order: \" + order);\n            } else {\n                System.out.println(\"Picked up: \" + order + \", number \" + (place + 1) + \" in line\");\n                waiting.remove(order);\n            }\n        }\n        System.out.println(\"Still waiting: \" + waiting);\n    }\n}\n","solution":"// ==== Order.java ====\npublic class Order {\n    private String customer;\n    private String item;\n\n    public Order(String customer, String item) {\n        this.customer = customer;\n        this.item = item;\n    }\n\n    public boolean equals(Object compared) {\n        if (this == compared) {\n            return true;\n        }\n        if (!(compared instanceof Order)) {\n            return false;\n        }\n        Order other = (Order) compared;\n        return this.customer.equals(other.customer) && this.item.equals(other.item);\n    }\n\n    public String toString() {\n        return this.item + \" for \" + this.customer;\n    }\n}\n\n// ==== Main.java ====\nimport java.util.ArrayList;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Order> waiting = new ArrayList<>();\n        waiting.add(new Order(\"Ada\", \"croissant\"));\n        waiting.add(new Order(\"Ben\", \"bagel\"));\n        waiting.add(new Order(\"Cy\", \"muffin\"));\n        waiting.add(new Order(\"Di\", \"bagel\"));\n\n        Scanner scanner = new Scanner(System.in);\n        while (true) {\n            String line = scanner.nextLine();\n            if (line.isEmpty()) {\n                break;\n            }\n            String[] parts = line.split(\" \");\n            Order order = new Order(parts[0], parts[1]);\n            int place = waiting.indexOf(order);\n            if (place == -1) {\n                System.out.println(\"No order: \" + order);\n            } else {\n                System.out.println(\"Picked up: \" + order + \", number \" + (place + 1) + \" in line\");\n                waiting.remove(order);\n            }\n        }\n        System.out.println(\"Still waiting: \" + waiting);\n    }\n}\n","hints":["`indexOf` and `remove` call `equals`, so `Main` needs no change. Once `Order` has an `equals` that compares the customer and the item, they find the order in the list that's equal to the one typed in.","Write it as in the previous step: `public boolean equals(Object compared)`, the `this ==` check, `instanceof Order`, the cast, and `return this.customer.equals(other.customer) && this.item.equals(other.item);`."],"tests":[{"name":"Test 1","stdin":"Ben bagel\nAda muffin\nDi bagel\n\n","expect":"Picked up: bagel for Ben, number 2 in line\nNo order: muffin for Ada\nPicked up: bagel for Di, number 3 in line\nStill waiting: [croissant for Ada, muffin for Cy]","hidden":false},{"name":"Test 2","stdin":"Cy muffin\nCy muffin\nAda croissant\n\n","expect":"Picked up: muffin for Cy, number 3 in line\nNo order: muffin for Cy\nPicked up: croissant for Ada, number 1 in line\nStill waiting: [bagel for Ben, bagel for Di]","hidden":true},{"name":"Test 3","stdin":"\n","expect":"Still waiting: [croissant for Ada, bagel for Ben, muffin for Cy, bagel for Di]","hidden":true},{"name":"Test 4","stdin":"Ben muffin\nDi bagel\nBen bagel\n\n","expect":"No order: muffin for Ben\nPicked up: bagel for Di, number 4 in line\nPicked up: bagel for Ben, number 2 in line\nStill waiting: [croissant for Ada, muffin for Cy]","hidden":true},{"name":"Test 5","stdin":"","call":"Order order = new Order(\"Ben\", \"bagel\");\nSystem.out.println(order.equals(new Order(\"Di\", \"bagel\")));\nSystem.out.println(order.equals(new Order(\"Ben\", \"muffin\")));\nSystem.out.println(order.equals(\"bagel for Ben\"));\nSystem.out.println(order.equals(order));\n","expect":"false\nfalse\nfalse\ntrue","hidden":true}],"require":[{"pattern":"\\bpublic\\s+boolean\\s+equals\\s*\\(\\s*Object\\s+\\w+\\s*\\)","message":"Write the header exactly as `public boolean equals(Object compared)`: `indexOf` and `remove` use only an equals with that header."},{"pattern":"\\binstanceof\\s+Order\\b","message":"Check with `instanceof Order` that the compared object is an order, before the cast."}],"forbid":[],"more":[{"task":"The lost and found keeps the things people have left behind in a list, and `Item.java` (with `equals`) is ready. In `Main.java`, read lines such as `red scarf` (a color and a thing) until an empty line. For each, make an `Item`. If an equal item is in the list, remove it from the list and print `Returned: ` and the item; if not, print `No ` and the item and ` here`. At the end, print how many items are left. Let `contains` and `remove` do the searching, without a loop over the list. For the input shown below, the program prints:\n\n```\nReturned: red scarf\nNo green hat here\nReturned: red scarf\nNo red scarf here\nItems left: 2\n```\n","kind":"code","seed":"// ==== Main.java ====\nimport java.util.ArrayList;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Item> found = new ArrayList<>();\n        found.add(new Item(\"blue\", \"umbrella\"));\n        found.add(new Item(\"red\", \"scarf\"));\n        found.add(new Item(\"black\", \"glove\"));\n        found.add(new Item(\"red\", \"scarf\"));\n\n        Scanner scanner = new Scanner(System.in);\n\n    }\n}\n\n// ==== Item.java ====\npublic class Item {\n    private String color;\n    private String thing;\n\n    public Item(String color, String thing) {\n        this.color = color;\n        this.thing = thing;\n    }\n\n    public boolean equals(Object compared) {\n        if (this == compared) {\n            return true;\n        }\n        if (!(compared instanceof Item)) {\n            return false;\n        }\n        Item other = (Item) compared;\n        return this.color.equals(other.color) && this.thing.equals(other.thing);\n    }\n\n    public String toString() {\n        return this.color + \" \" + this.thing;\n    }\n}\n","solution":"// ==== Main.java ====\nimport java.util.ArrayList;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Item> found = new ArrayList<>();\n        found.add(new Item(\"blue\", \"umbrella\"));\n        found.add(new Item(\"red\", \"scarf\"));\n        found.add(new Item(\"black\", \"glove\"));\n        found.add(new Item(\"red\", \"scarf\"));\n\n        Scanner scanner = new Scanner(System.in);\n        while (true) {\n            String line = scanner.nextLine();\n            if (line.isEmpty()) {\n                break;\n            }\n            String[] parts = line.split(\" \");\n            Item item = new Item(parts[0], parts[1]);\n            if (found.contains(item)) {\n                found.remove(item);\n                System.out.println(\"Returned: \" + item);\n            } else {\n                System.out.println(\"No \" + item + \" here\");\n            }\n        }\n        System.out.println(\"Items left: \" + found.size());\n    }\n}\n\n// ==== Item.java ====\npublic class Item {\n    private String color;\n    private String thing;\n\n    public Item(String color, String thing) {\n        this.color = color;\n        this.thing = thing;\n    }\n\n    public boolean equals(Object compared) {\n        if (this == compared) {\n            return true;\n        }\n        if (!(compared instanceof Item)) {\n            return false;\n        }\n        Item other = (Item) compared;\n        return this.color.equals(other.color) && this.thing.equals(other.thing);\n    }\n\n    public String toString() {\n        return this.color + \" \" + this.thing;\n    }\n}\n","hints":["Read in a `while (true)` loop that breaks at the empty line. Split each line at the space and make the item: `Item item = new Item(parts[0], parts[1]);`.","`if (found.contains(item))`, then `found.remove(item);` and print `\"Returned: \" + item`. The new item isn't the object in the list, but it's equal to it, and that's all `contains` and `remove` need."],"tests":[{"name":"Test 1","stdin":"red scarf\ngreen hat\nred scarf\nred scarf\n\n","expect":"Returned: red scarf\nNo green hat here\nReturned: red scarf\nNo red scarf here\nItems left: 2","hidden":false},{"name":"Test 2","stdin":"black glove\nblue umbrella\nblack glove\n\n","expect":"Returned: black glove\nReturned: blue umbrella\nNo black glove here\nItems left: 2","hidden":true},{"name":"Test 3","stdin":"\n","expect":"Items left: 4","hidden":true},{"name":"Test 4","stdin":"red umbrella\nblue scarf\nred scarf\n\n","expect":"No red umbrella here\nNo blue scarf here\nReturned: red scarf\nItems left: 3","hidden":true}],"require":[{"pattern":"\\.contains\\s*\\(","message":"Check whether an equal item is in the list with `contains`."},{"pattern":"\\.remove\\s*\\(","message":"Take the item out of the list with `remove`."}],"forbid":[{"pattern":"\\bfor\\s*\\(","message":"Let `contains` and `remove` do the searching, without a loop over the list."}]},{"task":"What does this program print? `Tag` has no `equals` of its own.\n","kind":"predict","seed":"import java.util.ArrayList;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Tag> tags = new ArrayList<>();\n        Tag urgent = new Tag(\"urgent\");\n        tags.add(urgent);\n        tags.add(new Tag(\"home\"));\n        System.out.println(tags.contains(urgent));\n        System.out.println(tags.contains(new Tag(\"home\")));\n        System.out.println(tags.indexOf(urgent));\n        System.out.println(tags.indexOf(new Tag(\"urgent\")));\n    }\n}\n// ==== Tag.java ====\npublic class Tag {\n    private String name;\n\n    public Tag(String name) {\n        this.name = name;\n    }\n\n    public String toString() {\n        return \"#\" + this.name;\n    }\n}\n","solution":"import java.util.ArrayList;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Tag> tags = new ArrayList<>();\n        Tag urgent = new Tag(\"urgent\");\n        tags.add(urgent);\n        tags.add(new Tag(\"home\"));\n        System.out.println(tags.contains(urgent));\n        System.out.println(tags.contains(new Tag(\"home\")));\n        System.out.println(tags.indexOf(urgent));\n        System.out.println(tags.indexOf(new Tag(\"urgent\")));\n    }\n}\n// ==== Tag.java ====\npublic class Tag {\n    private String name;\n\n    public Tag(String name) {\n        this.name = name;\n    }\n\n    public String toString() {\n        return \"#\" + this.name;\n    }\n}\n","hints":["Without an `equals` of its own, Tag uses the one every class gets, which does the same as `==`: an object is equal only to itself.","`urgent` is the very object in the list, at index 0, so it's found. Each `new Tag(...)` is a new object that isn't in the list, so it's never found."],"tests":[{"name":"Output","stdin":"","expect":"true\nfalse\n0\n-1","hidden":false}],"require":[],"forbid":[],"lines":["true","false","0","-1"]}]}