{"id":"libraries-and-tools-daos","slug":"data-access-objects","title":"Data access objects","text":"A program that keeps data for longer than one run stores it somewhere: in files (module 43), in a database (step 4), or on a server somewhere else. Where it's stored is a decision that can change. A shop's program might start with a file, move to a database when it grows, and use a list in memory in its tests.\n\nIf code all over the program reads and writes the file itself, each such change means changing all of that code. A **data access object**, a **DAO** for short, puts everything about storing in one class. The rest of the program asks it for the data and hands it new data, and never knows where the data lives. It's the same idea as module 25's split between the user interface and the program's logic, one layer further down.\n\n### The interface\n\nA DAO is usually described by an interface (module 35): the things it can do, with no word about how. A recipe box keeps recipes:\n\n```java\npublic interface RecipeDao {\n    List<Recipe> list();\n    int add(String name, int minutes);\n    Recipe findById(int id);\n}\n```\n\n- `list()` returns every recipe.\n- `add(name, minutes)` stores a new recipe and returns the **id** it got: a number that names this recipe and no other.\n- `findById(id)` returns the recipe with that id, or `null` when there's none.\n\nWhy ids? Two recipes can have the same name, and a name can change. A table usually has an id column whose numbers the database hands out, and the rest of the program uses that number to say which one it means: \"show recipe 3\", \"remove recipe 5\". The DAO hands out the ids, never the caller.\n\n### An implementation that keeps everything in memory\n\nThe simplest DAO keeps its recipes in a list. Its data is gone when the program ends, but everything else works as with a real database, which makes it right for trying a program out and for tests:\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        RecipeDao recipes = new InMemoryRecipeDao();\n        int curry = recipes.add(\"Chickpea curry\", 40);\n        recipes.add(\"Herb flatbread\", 20);\n        System.out.println(\"The curry got id \" + curry);\n        System.out.println(recipes.list());\n        System.out.println(recipes.findById(2));\n        System.out.println(recipes.findById(7));\n    }\n}\n// ==== RecipeDao.java ====\nimport java.util.List;\n\npublic interface RecipeDao {\n    List<Recipe> list();\n    int add(String name, int minutes);\n    Recipe findById(int id);\n}\n// ==== InMemoryRecipeDao.java ====\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class InMemoryRecipeDao implements RecipeDao {\n    private List<Recipe> recipes;\n    private int nextId;\n\n    public InMemoryRecipeDao() {\n        this.recipes = new ArrayList<>();\n        this.nextId = 1;\n    }\n\n    @Override\n    public List<Recipe> list() {\n        return new ArrayList<>(this.recipes);\n    }\n\n    @Override\n    public int add(String name, int minutes) {\n        int id = this.nextId;\n        this.nextId++;\n        this.recipes.add(new Recipe(id, name, minutes));\n        return id;\n    }\n\n    @Override\n    public Recipe findById(int id) {\n        for (Recipe recipe : this.recipes) {\n            if (recipe.getId() == id) {\n                return recipe;\n            }\n        }\n        return null;\n    }\n}\n// ==== Recipe.java ====\npublic class Recipe {\n    private int id;\n    private String name;\n    private int minutes;\n\n    public Recipe(int id, String name, int minutes) {\n        this.id = id;\n        this.name = name;\n        this.minutes = minutes;\n    }\n\n    public int getId() {\n        return this.id;\n    }\n\n    public String getName() {\n        return this.name;\n    }\n\n    public int getMinutes() {\n        return this.minutes;\n    }\n\n    @Override\n    public String toString() {\n        return \"#\" + this.id + \" \" + this.name + \", \" + this.minutes + \" min\";\n    }\n}\n```\n\n```output\nThe curry got id 1\n[#1 Chickpea curry, 40 min, #2 Herb flatbread, 20 min]\n#2 Herb flatbread, 20 min\nnull\n```\n\n\n<figure class=\"uml\"><div class=\"uml-scroll\" tabindex=\"0\" role=\"group\" aria-label=\"Class diagram of RecipeDao, InMemoryRecipeDao and Recipe\">\n<svg class=\"uml-svg\" viewBox=\"0 0 399 240\" width=\"399\" height=\"240\" style=\"width:24.94rem;min-width:22.86rem;aspect-ratio:399/240\" font-size=\"12\" aria-hidden=\"true\" focusable=\"false\"><path class=\"u-edge u-dash\" fill=\"none\" d=\"M147.5 113L147.5 146\"/><path class=\"u-edge\" fill=\"none\" d=\"M235 182L283 182\"/><path class=\"u-tri\" d=\"M147.5 102L140.5 113L154.5 113Z\"/><path class=\"u-edge\" fill=\"none\" d=\"M273 187.5L283 182L273 176.5\"/><rect class=\"u-bg\" fill=\"none\" x=\"6\" y=\"6\" width=\"283\" height=\"96\"/><rect class=\"u-head\" fill=\"none\" x=\"6\" y=\"6\" width=\"283\" height=\"40\"/><text x=\"147.5\" y=\"22\" text-anchor=\"middle\" class=\"u-st\">«interface»</text><text x=\"147.5\" y=\"38\" text-anchor=\"middle\" class=\"u-name\">RecipeDao</text><text x=\"14\" y=\"62\">+list(): List&lt;Recipe&gt;</text><text x=\"14\" y=\"78\">+add(name: String, minutes: int): int</text><text x=\"14\" y=\"94\">+findById(id: int): Recipe</text><path class=\"u-sep\" fill=\"none\" d=\"M6 46h283\"/><rect class=\"u-frame\" fill=\"none\" x=\"6\" y=\"6\" width=\"283\" height=\"96\"/><rect class=\"u-bg\" fill=\"none\" x=\"60\" y=\"146\" width=\"175\" height=\"72\"/><rect class=\"u-head\" fill=\"none\" x=\"60\" y=\"146\" width=\"175\" height=\"24\"/><text x=\"147.5\" y=\"162\" text-anchor=\"middle\" class=\"u-name\">InMemoryRecipeDao</text><text x=\"68\" y=\"186\">-recipes: List&lt;Recipe&gt;</text><text x=\"68\" y=\"202\">-nextId: int</text><path class=\"u-sep\" fill=\"none\" d=\"M60 170h175M60 210h175\"/><rect class=\"u-frame\" fill=\"none\" x=\"60\" y=\"146\" width=\"175\" height=\"72\"/><rect class=\"u-bg\" fill=\"none\" x=\"283\" y=\"146\" width=\"110\" height=\"88\"/><rect class=\"u-head\" fill=\"none\" x=\"283\" y=\"146\" width=\"110\" height=\"24\"/><text x=\"338\" y=\"162\" text-anchor=\"middle\" class=\"u-name\">Recipe</text><text x=\"291\" y=\"186\">-id: int</text><text x=\"291\" y=\"202\">-name: String</text><text x=\"291\" y=\"218\">-minutes: int</text><path class=\"u-sep\" fill=\"none\" d=\"M283 170h110M283 226h110\"/><rect class=\"u-frame\" fill=\"none\" x=\"283\" y=\"146\" width=\"110\" height=\"88\"/><text x=\"277\" y=\"175\" text-anchor=\"end\" class=\"u-mult\">*</text></svg>\n</div><details class=\"uml-text\"><summary>The diagram as text</summary><ul><li><strong>RecipeDao</strong>, an interface<ul><li>public method <code>list(): List&lt;Recipe&gt;</code></li><li>public method <code>add(name: String, minutes: int): int</code></li><li>public method <code>findById(id: int): Recipe</code></li></ul></li><li><strong>InMemoryRecipeDao</strong>, a class that implements RecipeDao<ul><li>private field <code>recipes: List&lt;Recipe&gt;</code></li><li>private field <code>nextId: int</code></li></ul></li><li><strong>Recipe</strong>, a class<ul><li>private field <code>id: int</code></li><li>private field <code>name: String</code></li><li>private field <code>minutes: int</code></li></ul></li></ul><p>Connections:</p><ul><li>Each InMemoryRecipeDao has any number of Recipe objects.</li></ul></details></figure>\n\n\n- **Ids grow from 1.** `nextId` is the id the next recipe gets. `add` takes it and counts it up, so every recipe gets a new one. A database table with an identity column, like the one in step 4, does the same: H2 doesn't hand out a removed row's id again, even after the program restarts. That matters because an old \"recipe 5\" written down somewhere must never come to mean another recipe.\n- **`list()` returns a new list** with the same recipes. If it returned `this.recipes` itself, a caller could `clear()` it, or add a recipe with any id it likes, past the DAO. A database's DAO also builds a new list for every call, so a caller can't tell the difference.\n- **`main` uses the interface.** The variable's type is `RecipeDao`; only the line with `new` names the class. Swap that one line for another DAO, and the rest of the program stays the same.\n\n### Changing and removing\n\nA DAO usually does two more things:\n\n```java\nboolean update(Recipe recipe);\nboolean remove(int id);\n```\n\n`update` stores the recipe it's given in place of the one with the same id, and `remove` removes the one with that id. Both return whether there was such a recipe. Together with `add` and the two ways of reading, these are often called **CRUD**: create, read, update and delete, the four things a program does with stored data.\n","task":"A bike repair shop keeps a queue of repair jobs. `RepairJob.java` and the interface `RepairJobDao.java` are ready. Write the class `InMemoryRepairJobDao`, which keeps the jobs in a list:\n\n- `list()` returns a new list with every job, in the order they were added\n- `add(bike, problem)` stores a new job that isn't ready yet, with the next id, and returns the id; the first id is 1\n- `findById(id)` returns the job with that id, or `null`\n\nEach DAO has ids of its own: a new DAO starts from 1 again. The program prints:\n\n```\n1 and 2\n[#1 red road bike: flat tire (waiting), #2 green cargo bike: squeaky brakes (waiting)]\n#2 green cargo bike: squeaky brakes (waiting)\nnull\n```\n","kind":"code","seed":"// ==== InMemoryRepairJobDao.java ====\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class InMemoryRepairJobDao implements RepairJobDao {\n\n    @Override\n    public List<RepairJob> list() {\n        return new ArrayList<>();\n    }\n\n    @Override\n    public int add(String bike, String problem) {\n        return 0;\n    }\n\n    @Override\n    public RepairJob findById(int id) {\n        return null;\n    }\n}\n\n// ==== RepairJobDao.java ====\nimport java.util.List;\n\npublic interface RepairJobDao {\n    List<RepairJob> list();\n    int add(String bike, String problem);\n    RepairJob findById(int id);\n}\n\n// ==== RepairJob.java ====\npublic class RepairJob {\n    private int id;\n    private String bike;\n    private String problem;\n    private boolean ready;\n\n    public RepairJob(int id, String bike, String problem, boolean ready) {\n        this.id = id;\n        this.bike = bike;\n        this.problem = problem;\n        this.ready = ready;\n    }\n\n    public int getId() {\n        return this.id;\n    }\n\n    public String getBike() {\n        return this.bike;\n    }\n\n    public String getProblem() {\n        return this.problem;\n    }\n\n    public boolean isReady() {\n        return this.ready;\n    }\n\n    @Override\n    public String toString() {\n        String state = \"waiting\";\n        if (this.ready) {\n            state = \"ready\";\n        }\n        return \"#\" + this.id + \" \" + this.bike + \": \" + this.problem + \" (\" + state + \")\";\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        RepairJobDao queue = new InMemoryRepairJobDao();\n        int first = queue.add(\"red road bike\", \"flat tire\");\n        int second = queue.add(\"green cargo bike\", \"squeaky brakes\");\n        System.out.println(first + \" and \" + second);\n        System.out.println(queue.list());\n        System.out.println(queue.findById(2));\n        System.out.println(queue.findById(5));\n    }\n}\n","solution":"// ==== InMemoryRepairJobDao.java ====\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class InMemoryRepairJobDao implements RepairJobDao {\n    private List<RepairJob> jobs;\n    private int nextId;\n\n    public InMemoryRepairJobDao() {\n        this.jobs = new ArrayList<>();\n        this.nextId = 1;\n    }\n\n    @Override\n    public List<RepairJob> list() {\n        return new ArrayList<>(this.jobs);\n    }\n\n    @Override\n    public int add(String bike, String problem) {\n        int id = this.nextId;\n        this.nextId++;\n        this.jobs.add(new RepairJob(id, bike, problem, false));\n        return id;\n    }\n\n    @Override\n    public RepairJob findById(int id) {\n        for (RepairJob job : this.jobs) {\n            if (job.getId() == id) {\n                return job;\n            }\n        }\n        return null;\n    }\n}\n\n// ==== RepairJobDao.java ====\nimport java.util.List;\n\npublic interface RepairJobDao {\n    List<RepairJob> list();\n    int add(String bike, String problem);\n    RepairJob findById(int id);\n}\n\n// ==== RepairJob.java ====\npublic class RepairJob {\n    private int id;\n    private String bike;\n    private String problem;\n    private boolean ready;\n\n    public RepairJob(int id, String bike, String problem, boolean ready) {\n        this.id = id;\n        this.bike = bike;\n        this.problem = problem;\n        this.ready = ready;\n    }\n\n    public int getId() {\n        return this.id;\n    }\n\n    public String getBike() {\n        return this.bike;\n    }\n\n    public String getProblem() {\n        return this.problem;\n    }\n\n    public boolean isReady() {\n        return this.ready;\n    }\n\n    @Override\n    public String toString() {\n        String state = \"waiting\";\n        if (this.ready) {\n            state = \"ready\";\n        }\n        return \"#\" + this.id + \" \" + this.bike + \": \" + this.problem + \" (\" + state + \")\";\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        RepairJobDao queue = new InMemoryRepairJobDao();\n        int first = queue.add(\"red road bike\", \"flat tire\");\n        int second = queue.add(\"green cargo bike\", \"squeaky brakes\");\n        System.out.println(first + \" and \" + second);\n        System.out.println(queue.list());\n        System.out.println(queue.findById(2));\n        System.out.println(queue.findById(5));\n    }\n}\n","hints":["Follow the recipe box's `InMemoryRecipeDao`: two instance variables, a `List<RepairJob>` and the next id, both set in the constructor. The id variable must not be `static`, since each DAO counts on its own.","`add` keeps the id in a variable, counts `nextId` up, stores `new RepairJob(id, bike, problem, false)` and returns the id. `list` returns `new ArrayList<>(this.jobs)`."],"tests":[{"name":"Two jobs","stdin":"","expect":"1 and 2\n[#1 red road bike: flat tire (waiting), #2 green cargo bike: squeaky brakes (waiting)]\n#2 green cargo bike: squeaky brakes (waiting)\nnull","hidden":false},{"name":"Test 2","stdin":"","call":"RepairJobDao queue = new InMemoryRepairJobDao();\nSystem.out.println(queue.list());\nqueue.add(\"blue tandem\", \"loose chain\");\nqueue.list().clear();\nSystem.out.println(queue.list().size());\nSystem.out.println(queue.findById(1));\n","expect":"[]\n1\n#1 blue tandem: loose chain (waiting)","hidden":true},{"name":"Test 3","stdin":"","call":"RepairJobDao first = new InMemoryRepairJobDao();\nfirst.add(\"black fixie\", \"worn saddle\");\nfirst.add(\"orange kids bike\", \"wobbly pedal\");\nRepairJobDao second = new InMemoryRepairJobDao();\nSystem.out.println(second.add(\"silver e-bike\", \"dead light\"));\nSystem.out.println(first.add(\"white racer\", \"bent fork\"));\nSystem.out.println(first.findById(3));\nSystem.out.println(second.findById(2));\n","expect":"1\n3\n#3 white racer: bent fork (waiting)\nnull","hidden":true}],"require":[],"forbid":[],"more":[{"task":"The repair queue needs to remove jobs: a customer took their bike home unfixed. The interface now has `boolean remove(int id)`, and `list`, `add` and `findById` are done. Write `remove` in `InMemoryRepairJobDao`: it removes the job with that id and returns `true`, or returns `false` when there's no such job.\n\nIds are never handed out again: after job 3 is removed, the next new job still gets the next id, not 3. The program prints:\n\n```\ntrue\nfalse\nnew id 4\n[#1 red road bike: flat tire (waiting), #3 yellow folding bike: bent wheel (waiting), #4 black fixie: worn saddle (waiting)]\n```\n","kind":"code","seed":"// ==== InMemoryRepairJobDao.java ====\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class InMemoryRepairJobDao implements RepairJobDao {\n    private List<RepairJob> jobs;\n    private int nextId;\n\n    public InMemoryRepairJobDao() {\n        this.jobs = new ArrayList<>();\n        this.nextId = 1;\n    }\n\n    @Override\n    public List<RepairJob> list() {\n        return new ArrayList<>(this.jobs);\n    }\n\n    @Override\n    public int add(String bike, String problem) {\n        int id = this.nextId;\n        this.nextId++;\n        this.jobs.add(new RepairJob(id, bike, problem, false));\n        return id;\n    }\n\n    @Override\n    public RepairJob findById(int id) {\n        for (RepairJob job : this.jobs) {\n            if (job.getId() == id) {\n                return job;\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public boolean remove(int id) {\n        return false;\n    }\n}\n\n// ==== RepairJobDao.java ====\nimport java.util.List;\n\npublic interface RepairJobDao {\n    List<RepairJob> list();\n    int add(String bike, String problem);\n    RepairJob findById(int id);\n    boolean remove(int id);\n}\n\n// ==== RepairJob.java ====\npublic class RepairJob {\n    private int id;\n    private String bike;\n    private String problem;\n    private boolean ready;\n\n    public RepairJob(int id, String bike, String problem, boolean ready) {\n        this.id = id;\n        this.bike = bike;\n        this.problem = problem;\n        this.ready = ready;\n    }\n\n    public int getId() {\n        return this.id;\n    }\n\n    public String getBike() {\n        return this.bike;\n    }\n\n    public String getProblem() {\n        return this.problem;\n    }\n\n    public boolean isReady() {\n        return this.ready;\n    }\n\n    @Override\n    public String toString() {\n        String state = \"waiting\";\n        if (this.ready) {\n            state = \"ready\";\n        }\n        return \"#\" + this.id + \" \" + this.bike + \": \" + this.problem + \" (\" + state + \")\";\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        RepairJobDao queue = new InMemoryRepairJobDao();\n        queue.add(\"red road bike\", \"flat tire\");\n        queue.add(\"green cargo bike\", \"squeaky brakes\");\n        queue.add(\"yellow folding bike\", \"bent wheel\");\n        System.out.println(queue.remove(2));\n        System.out.println(queue.remove(2));\n        int next = queue.add(\"black fixie\", \"worn saddle\");\n        System.out.println(\"new id \" + next);\n        System.out.println(queue.list());\n    }\n}\n","solution":"// ==== InMemoryRepairJobDao.java ====\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class InMemoryRepairJobDao implements RepairJobDao {\n    private List<RepairJob> jobs;\n    private int nextId;\n\n    public InMemoryRepairJobDao() {\n        this.jobs = new ArrayList<>();\n        this.nextId = 1;\n    }\n\n    @Override\n    public List<RepairJob> list() {\n        return new ArrayList<>(this.jobs);\n    }\n\n    @Override\n    public int add(String bike, String problem) {\n        int id = this.nextId;\n        this.nextId++;\n        this.jobs.add(new RepairJob(id, bike, problem, false));\n        return id;\n    }\n\n    @Override\n    public RepairJob findById(int id) {\n        for (RepairJob job : this.jobs) {\n            if (job.getId() == id) {\n                return job;\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public boolean remove(int id) {\n        RepairJob job = findById(id);\n        if (job == null) {\n            return false;\n        }\n        this.jobs.remove(job);\n        return true;\n    }\n}\n\n// ==== RepairJobDao.java ====\nimport java.util.List;\n\npublic interface RepairJobDao {\n    List<RepairJob> list();\n    int add(String bike, String problem);\n    RepairJob findById(int id);\n    boolean remove(int id);\n}\n\n// ==== RepairJob.java ====\npublic class RepairJob {\n    private int id;\n    private String bike;\n    private String problem;\n    private boolean ready;\n\n    public RepairJob(int id, String bike, String problem, boolean ready) {\n        this.id = id;\n        this.bike = bike;\n        this.problem = problem;\n        this.ready = ready;\n    }\n\n    public int getId() {\n        return this.id;\n    }\n\n    public String getBike() {\n        return this.bike;\n    }\n\n    public String getProblem() {\n        return this.problem;\n    }\n\n    public boolean isReady() {\n        return this.ready;\n    }\n\n    @Override\n    public String toString() {\n        String state = \"waiting\";\n        if (this.ready) {\n            state = \"ready\";\n        }\n        return \"#\" + this.id + \" \" + this.bike + \": \" + this.problem + \" (\" + state + \")\";\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        RepairJobDao queue = new InMemoryRepairJobDao();\n        queue.add(\"red road bike\", \"flat tire\");\n        queue.add(\"green cargo bike\", \"squeaky brakes\");\n        queue.add(\"yellow folding bike\", \"bent wheel\");\n        System.out.println(queue.remove(2));\n        System.out.println(queue.remove(2));\n        int next = queue.add(\"black fixie\", \"worn saddle\");\n        System.out.println(\"new id \" + next);\n        System.out.println(queue.list());\n    }\n}\n","hints":["`findById` already finds the job. If it returns `null`, there's nothing to remove.","`this.jobs.remove(job)` removes that very object from the list. Don't touch `nextId`: it keeps counting up, so no id comes back."],"tests":[{"name":"Remove job 2 twice","stdin":"","expect":"true\nfalse\nnew id 4\n[#1 red road bike: flat tire (waiting), #3 yellow folding bike: bent wheel (waiting), #4 black fixie: worn saddle (waiting)]","hidden":false},{"name":"Test 2","stdin":"","call":"RepairJobDao queue = new InMemoryRepairJobDao();\nSystem.out.println(queue.remove(1));\nqueue.add(\"blue tandem\", \"loose chain\");\nqueue.add(\"silver e-bike\", \"dead light\");\nSystem.out.println(queue.remove(2));\nSystem.out.println(queue.add(\"white racer\", \"bent fork\"));\nSystem.out.println(queue.remove(1));\nSystem.out.println(queue.list());\nSystem.out.println(queue.findById(1));\n","expect":"false\ntrue\n3\ntrue\n[#3 white racer: bent fork (waiting)]\nnull","hidden":true}],"require":[],"forbid":[]},{"task":"A mechanic finishes a job, and the queue must show it as ready. The interface now has `boolean update(RepairJob job)`: it stores the job it's given in place of the stored job with the same id, at the same place in the list, and returns `true`; when no stored job has that id, it changes nothing and returns `false`. Write `update` in `InMemoryRepairJobDao`.\n\nA RepairJob can't be changed once it's made, so the program makes a new one with the same id, bike and problem, and `true` for ready. The program prints:\n\n```\ntrue\nfalse\n[#1 red road bike: flat tire (ready), #2 green cargo bike: squeaky brakes (waiting)]\n```\n","kind":"code","seed":"// ==== InMemoryRepairJobDao.java ====\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class InMemoryRepairJobDao implements RepairJobDao {\n    private List<RepairJob> jobs;\n    private int nextId;\n\n    public InMemoryRepairJobDao() {\n        this.jobs = new ArrayList<>();\n        this.nextId = 1;\n    }\n\n    @Override\n    public List<RepairJob> list() {\n        return new ArrayList<>(this.jobs);\n    }\n\n    @Override\n    public int add(String bike, String problem) {\n        int id = this.nextId;\n        this.nextId++;\n        this.jobs.add(new RepairJob(id, bike, problem, false));\n        return id;\n    }\n\n    @Override\n    public RepairJob findById(int id) {\n        for (RepairJob job : this.jobs) {\n            if (job.getId() == id) {\n                return job;\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public boolean update(RepairJob job) {\n        return false;\n    }\n\n    @Override\n    public boolean remove(int id) {\n        RepairJob job = findById(id);\n        if (job == null) {\n            return false;\n        }\n        this.jobs.remove(job);\n        return true;\n    }\n}\n\n// ==== RepairJobDao.java ====\nimport java.util.List;\n\npublic interface RepairJobDao {\n    List<RepairJob> list();\n    int add(String bike, String problem);\n    RepairJob findById(int id);\n    boolean update(RepairJob job);\n    boolean remove(int id);\n}\n\n// ==== RepairJob.java ====\npublic class RepairJob {\n    private int id;\n    private String bike;\n    private String problem;\n    private boolean ready;\n\n    public RepairJob(int id, String bike, String problem, boolean ready) {\n        this.id = id;\n        this.bike = bike;\n        this.problem = problem;\n        this.ready = ready;\n    }\n\n    public int getId() {\n        return this.id;\n    }\n\n    public String getBike() {\n        return this.bike;\n    }\n\n    public String getProblem() {\n        return this.problem;\n    }\n\n    public boolean isReady() {\n        return this.ready;\n    }\n\n    @Override\n    public String toString() {\n        String state = \"waiting\";\n        if (this.ready) {\n            state = \"ready\";\n        }\n        return \"#\" + this.id + \" \" + this.bike + \": \" + this.problem + \" (\" + state + \")\";\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        RepairJobDao queue = new InMemoryRepairJobDao();\n        queue.add(\"red road bike\", \"flat tire\");\n        queue.add(\"green cargo bike\", \"squeaky brakes\");\n        RepairJob job = queue.findById(1);\n        RepairJob fixed = new RepairJob(job.getId(), job.getBike(), job.getProblem(), true);\n        System.out.println(queue.update(fixed));\n        System.out.println(queue.update(new RepairJob(9, \"old town bike\", \"rusty chain\", true)));\n        System.out.println(queue.list());\n    }\n}\n","solution":"// ==== InMemoryRepairJobDao.java ====\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class InMemoryRepairJobDao implements RepairJobDao {\n    private List<RepairJob> jobs;\n    private int nextId;\n\n    public InMemoryRepairJobDao() {\n        this.jobs = new ArrayList<>();\n        this.nextId = 1;\n    }\n\n    @Override\n    public List<RepairJob> list() {\n        return new ArrayList<>(this.jobs);\n    }\n\n    @Override\n    public int add(String bike, String problem) {\n        int id = this.nextId;\n        this.nextId++;\n        this.jobs.add(new RepairJob(id, bike, problem, false));\n        return id;\n    }\n\n    @Override\n    public RepairJob findById(int id) {\n        for (RepairJob job : this.jobs) {\n            if (job.getId() == id) {\n                return job;\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public boolean update(RepairJob job) {\n        for (int i = 0; i < this.jobs.size(); i++) {\n            if (this.jobs.get(i).getId() == job.getId()) {\n                this.jobs.set(i, job);\n                return true;\n            }\n        }\n        return false;\n    }\n\n    @Override\n    public boolean remove(int id) {\n        RepairJob job = findById(id);\n        if (job == null) {\n            return false;\n        }\n        this.jobs.remove(job);\n        return true;\n    }\n}\n\n// ==== RepairJobDao.java ====\nimport java.util.List;\n\npublic interface RepairJobDao {\n    List<RepairJob> list();\n    int add(String bike, String problem);\n    RepairJob findById(int id);\n    boolean update(RepairJob job);\n    boolean remove(int id);\n}\n\n// ==== RepairJob.java ====\npublic class RepairJob {\n    private int id;\n    private String bike;\n    private String problem;\n    private boolean ready;\n\n    public RepairJob(int id, String bike, String problem, boolean ready) {\n        this.id = id;\n        this.bike = bike;\n        this.problem = problem;\n        this.ready = ready;\n    }\n\n    public int getId() {\n        return this.id;\n    }\n\n    public String getBike() {\n        return this.bike;\n    }\n\n    public String getProblem() {\n        return this.problem;\n    }\n\n    public boolean isReady() {\n        return this.ready;\n    }\n\n    @Override\n    public String toString() {\n        String state = \"waiting\";\n        if (this.ready) {\n            state = \"ready\";\n        }\n        return \"#\" + this.id + \" \" + this.bike + \": \" + this.problem + \" (\" + state + \")\";\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        RepairJobDao queue = new InMemoryRepairJobDao();\n        queue.add(\"red road bike\", \"flat tire\");\n        queue.add(\"green cargo bike\", \"squeaky brakes\");\n        RepairJob job = queue.findById(1);\n        RepairJob fixed = new RepairJob(job.getId(), job.getBike(), job.getProblem(), true);\n        System.out.println(queue.update(fixed));\n        System.out.println(queue.update(new RepairJob(9, \"old town bike\", \"rusty chain\", true)));\n        System.out.println(queue.list());\n    }\n}\n","hints":["Go through the list by index, with a `for` loop from 0 to `size() - 1`, and compare each stored job's id with `job.getId()`.","`this.jobs.set(i, job)` puts the new job at index `i`, in place of the old one, so the order stays. Return `true` right after it, and `false` after the loop."],"tests":[{"name":"Job 1 is ready","stdin":"","expect":"true\nfalse\n[#1 red road bike: flat tire (ready), #2 green cargo bike: squeaky brakes (waiting)]","hidden":false},{"name":"Test 2","stdin":"","call":"RepairJobDao queue = new InMemoryRepairJobDao();\nqueue.add(\"blue tandem\", \"loose chain\");\nqueue.add(\"silver e-bike\", \"dead light\");\nqueue.add(\"white racer\", \"bent fork\");\nSystem.out.println(queue.update(new RepairJob(2, \"silver e-bike\", \"dead light and horn\", true)));\nSystem.out.println(queue.update(new RepairJob(4, \"white racer\", \"bent fork\", true)));\nSystem.out.println(queue.list());\nSystem.out.println(queue.findById(2).isReady());\nSystem.out.println(queue.add(\"black fixie\", \"worn saddle\"));\n","expect":"true\nfalse\n[#1 blue tandem: loose chain (waiting), #2 silver e-bike: dead light and horn (ready), #3 white racer: bent fork (waiting)]\ntrue\n4","hidden":true}],"require":[],"forbid":[]}]}