{"id":"class-diagrams-from-code","slug":"from-code","title":"From code to a box","text":"The last two steps went from a box to code. The other way is just as useful: when you join a project, or come back to your own program after a month, a box shows a class at a glance, without the method bodies in the way.\n\n### Drawing a class's box\n\nHere's another class of the recycling center's program. A compactor presses cans into blocks: it takes loads of cans, and each time it runs, it presses as many full blocks as it can and keeps the rest of the cans for the next run.\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        Compactor compactor = new Compactor(50);\n        compactor.load(120);\n        System.out.println(compactor.press());\n        compactor.load(35);\n        System.out.println(compactor.press());\n        System.out.println(compactor);\n    }\n}\n// ==== Compactor.java ====\npublic class Compactor {\n    private int cansPerBlock;\n    private int cans;\n    private int blocks;\n\n    public Compactor() {\n        this(50);\n    }\n\n    public Compactor(int cansPerBlock) {\n        this.cansPerBlock = cansPerBlock;\n        this.cans = 0;\n        this.blocks = 0;\n    }\n\n    public void load(int cans) {\n        if (cans > 0) {\n            this.cans += cans;\n        }\n    }\n\n    public int press() {\n        int made = this.blocksReady();\n        this.blocks += made;\n        this.cans -= made * this.cansPerBlock;\n        return made;\n    }\n\n    public int getBlocks() {\n        return this.blocks;\n    }\n\n    @Override\n    public String toString() {\n        return this.blocks + \" blocks, \" + this.cans + \" cans waiting\";\n    }\n\n    private int blocksReady() {\n        return this.cans / this.cansPerBlock;\n    }\n}\n```\n\n```output\n2\n1\n3 blocks, 5 cans waiting\n```\n\nGo through the class from the top, and write a line for each part of it:\n\n\n<figure class=\"uml\"><div class=\"uml-scroll\" tabindex=\"0\" role=\"group\" aria-label=\"Class diagram of Compactor\">\n<svg class=\"uml-svg\" viewBox=\"0 0 237 212\" width=\"237\" height=\"212\" style=\"width:14.82rem;min-width:13.58rem;aspect-ratio:237/212\" font-size=\"12\" aria-hidden=\"true\" focusable=\"false\"><rect class=\"u-bg\" fill=\"none\" x=\"6\" y=\"6\" width=\"225\" height=\"200\"/><rect class=\"u-head\" fill=\"none\" x=\"6\" y=\"6\" width=\"225\" height=\"24\"/><text x=\"118.5\" y=\"22\" text-anchor=\"middle\" class=\"u-name\">Compactor</text><text x=\"14\" y=\"46\">-cansPerBlock: int</text><text x=\"14\" y=\"62\">-cans: int</text><text x=\"14\" y=\"78\">-blocks: int</text><text x=\"14\" y=\"102\">+Compactor()</text><text x=\"14\" y=\"118\">+Compactor(cansPerBlock: int)</text><text x=\"14\" y=\"134\">+load(cans: int): void</text><text x=\"14\" y=\"150\">+press(): int</text><text x=\"14\" y=\"166\">+getBlocks(): int</text><text x=\"14\" y=\"182\">+toString(): String</text><text x=\"14\" y=\"198\">-blocksReady(): int</text><path class=\"u-sep\" fill=\"none\" d=\"M6 30h225M6 86h225\"/><rect class=\"u-frame\" fill=\"none\" x=\"6\" y=\"6\" width=\"225\" height=\"200\"/></svg>\n</div><details class=\"uml-text\"><summary>The diagram as text</summary><ul><li><strong>Compactor</strong>, a class<ul><li>private field <code>cansPerBlock: int</code></li><li>private field <code>cans: int</code></li><li>private field <code>blocks: int</code></li><li>public constructor <code>Compactor()</code></li><li>public constructor <code>Compactor(cansPerBlock: int)</code></li><li>public method <code>load(cans: int): void</code></li><li>public method <code>press(): int</code></li><li>public method <code>getBlocks(): int</code></li><li>public method <code>toString(): String</code></li><li>private method <code>blocksReady(): int</code></li></ul></li></ul></details></figure>\n\n\n- Each instance variable is a field line: sign, name, colon, type. The values it gets at the start (`this.cans = 0`) aren't shown.\n- Each constructor has a line of its own, so the two constructors are two lines. The one without parameters has empty parentheses.\n- Each method has a line: `public int press()` becomes `+press(): int`. `toString` is one of the class's methods, so it's there too.\n- The private helper `blocksReady` gets a `-`.\n- Nothing between the curly braces of a constructor or method is shown: no code, no `this`, no `if`. Neither is `@Override`.\n- This course's diagrams show the classes that the program makes objects of, and leave `Main` out.\n\n### What a box doesn't tell\n\nFrom the box, you know that `press()` returns an int. You don't know what the int means: the blocks it made, the cans it pressed, or the cans left over. You don't know that 50 cans make a block unless someone tells you, or that `load` ignores a negative number. Two classes with the same box can behave in completely different ways. A box shows a class's structure: what its objects hold and what they can be asked. What they do is in the code, and in the words that come with a diagram.\n\n### Using a class through its box\n\nA box is still all you need to write code that *uses* the class, once you know what its methods do. It gives each method's name, what to pass it and what comes back, so it tells you what type of variable can hold each answer:\n\n```java\nCompactor compactor = new Compactor();\ncompactor.load(80);\nint made = compactor.press();\nint total = compactor.getBlocks();\n```\n\n- `+Compactor()` says that `new Compactor()` works without parameters.\n- `+load(cans: int): void` takes an int and gives nothing back, so the call is a statement of its own.\n- `+press(): int` gives back an int, which can go into an `int` variable.\n- `-blocksReady(): int` is private, so this code can't call it. Only Compactor's own methods can.\n","task":"The pickups of step 1 have grown methods. Here's their box now:\n\n\n<figure class=\"uml\"><div class=\"uml-scroll\" tabindex=\"0\" role=\"group\" aria-label=\"Class diagram of Pickup\">\n<svg class=\"uml-svg\" viewBox=\"0 0 309 196\" width=\"309\" height=\"196\" style=\"width:19.32rem;min-width:17.71rem;aspect-ratio:309/196\" font-size=\"12\" aria-hidden=\"true\" focusable=\"false\"><rect class=\"u-bg\" fill=\"none\" x=\"6\" y=\"6\" width=\"297\" height=\"184\"/><rect class=\"u-head\" fill=\"none\" x=\"6\" y=\"6\" width=\"297\" height=\"24\"/><text x=\"154.5\" y=\"22\" text-anchor=\"middle\" class=\"u-name\">Pickup</text><text x=\"14\" y=\"46\">-address: String</text><text x=\"14\" y=\"62\">-kilos: double</text><text x=\"14\" y=\"78\">-done: boolean</text><text x=\"14\" y=\"102\">+Pickup(address: String, kilos: double)</text><text x=\"14\" y=\"118\">+getAddress(): String</text><text x=\"14\" y=\"134\">+getKilos(): double</text><text x=\"14\" y=\"150\">+isDone(): boolean</text><text x=\"14\" y=\"166\">+markDone(): void</text><text x=\"14\" y=\"182\">+toString(): String</text><path class=\"u-sep\" fill=\"none\" d=\"M6 30h297M6 86h297\"/><rect class=\"u-frame\" fill=\"none\" x=\"6\" y=\"6\" width=\"297\" height=\"184\"/></svg>\n</div><details class=\"uml-text\"><summary>The diagram as text</summary><ul><li><strong>Pickup</strong>, a class<ul><li>private field <code>address: String</code></li><li>private field <code>kilos: double</code></li><li>private field <code>done: boolean</code></li><li>public constructor <code>Pickup(address: String, kilos: double)</code></li><li>public method <code>getAddress(): String</code></li><li>public method <code>getKilos(): double</code></li><li>public method <code>isDone(): boolean</code></li><li>public method <code>markDone(): void</code></li><li>public method <code>toString(): String</code></li></ul></li></ul></details></figure>\n\n\nFill in the blanks in `main` from the box: the types of the two variables, and the name of the method that marks a pickup as done. The program should print:\n\n```\n35.5 true\n```\n","kind":"fill","seed":"public class Main {\n    public static void main(String[] args) {\n        Pickup pickup = new Pickup(\"12 Mill Road\", 35.5);\n        [[double]] kilos = pickup.getKilos();\n        pickup.[[markDone]]();\n        [[boolean]] done = pickup.isDone();\n        System.out.println(kilos + \" \" + done);\n    }\n}\n// ==== Pickup.java ====\npublic class Pickup {\n    private String address;\n    private double kilos;\n    private boolean done;\n\n    public Pickup(String address, double kilos) {\n        this.address = address;\n        this.kilos = kilos;\n        this.done = false;\n    }\n\n    public String getAddress() {\n        return this.address;\n    }\n\n    public double getKilos() {\n        return this.kilos;\n    }\n\n    public boolean isDone() {\n        return this.done;\n    }\n\n    public void markDone() {\n        this.done = true;\n    }\n\n    @Override\n    public String toString() {\n        return this.address + \": \" + this.kilos + \" kg\";\n    }\n}\n","solution":"public class Main {\n    public static void main(String[] args) {\n        Pickup pickup = new Pickup(\"12 Mill Road\", 35.5);\n        double kilos = pickup.getKilos();\n        pickup.markDone();\n        boolean done = pickup.isDone();\n        System.out.println(kilos + \" \" + done);\n    }\n}\n// ==== Pickup.java ====\npublic class Pickup {\n    private String address;\n    private double kilos;\n    private boolean done;\n\n    public Pickup(String address, double kilos) {\n        this.address = address;\n        this.kilos = kilos;\n        this.done = false;\n    }\n\n    public String getAddress() {\n        return this.address;\n    }\n\n    public double getKilos() {\n        return this.kilos;\n    }\n\n    public boolean isDone() {\n        return this.done;\n    }\n\n    public void markDone() {\n        this.done = true;\n    }\n\n    @Override\n    public String toString() {\n        return this.address + \": \" + this.kilos + \" kg\";\n    }\n}\n","hints":["The type after the colon is what a method gives back: `getKilos(): double` gives a double, so the variable that holds it is a `double`.","`isDone(): boolean` gives a `boolean`, and the method that marks the pickup is `markDone`, which returns nothing (`void`)."],"tests":[{"name":"Output","stdin":"","expect":"35.5 true","hidden":false}],"require":[],"forbid":[],"more":[{"task":"Another team wrote a compactor too. Its box is exactly the same as the one in the lesson, but it's a different class: this `load` refuses a load that would take the compactor over 150 cans, and this `press` makes at most one block per call and returns the number of cans it pressed. What does this program print?\n","kind":"predict","seed":"public class Main {\n    public static void main(String[] args) {\n        Compactor compactor = new Compactor(40);\n        compactor.load(90);\n        compactor.load(90);\n        System.out.println(compactor.press());\n        System.out.println(compactor.press());\n        System.out.println(compactor);\n    }\n}\n// ==== Compactor.java ====\npublic class Compactor {\n    private int cansPerBlock;\n    private int cans;\n    private int blocks;\n\n    public Compactor() {\n        this(50);\n    }\n\n    public Compactor(int cansPerBlock) {\n        this.cansPerBlock = cansPerBlock;\n        this.cans = 0;\n        this.blocks = 0;\n    }\n\n    public void load(int cans) {\n        if (this.cans + cans <= 150) {\n            this.cans += cans;\n        }\n    }\n\n    public int press() {\n        if (this.blocksReady() == 0) {\n            return 0;\n        }\n        this.blocks++;\n        this.cans -= this.cansPerBlock;\n        return this.cansPerBlock;\n    }\n\n    public int getBlocks() {\n        return this.blocks;\n    }\n\n    @Override\n    public String toString() {\n        return this.blocks + \" blocks, \" + this.cans + \" cans waiting\";\n    }\n\n    private int blocksReady() {\n        return this.cans / this.cansPerBlock;\n    }\n}\n","solution":"public class Main {\n    public static void main(String[] args) {\n        Compactor compactor = new Compactor(40);\n        compactor.load(90);\n        compactor.load(90);\n        System.out.println(compactor.press());\n        System.out.println(compactor.press());\n        System.out.println(compactor);\n    }\n}\n// ==== Compactor.java ====\npublic class Compactor {\n    private int cansPerBlock;\n    private int cans;\n    private int blocks;\n\n    public Compactor() {\n        this(50);\n    }\n\n    public Compactor(int cansPerBlock) {\n        this.cansPerBlock = cansPerBlock;\n        this.cans = 0;\n        this.blocks = 0;\n    }\n\n    public void load(int cans) {\n        if (this.cans + cans <= 150) {\n            this.cans += cans;\n        }\n    }\n\n    public int press() {\n        if (this.blocksReady() == 0) {\n            return 0;\n        }\n        this.blocks++;\n        this.cans -= this.cansPerBlock;\n        return this.cansPerBlock;\n    }\n\n    public int getBlocks() {\n        return this.blocks;\n    }\n\n    @Override\n    public String toString() {\n        return this.blocks + \" blocks, \" + this.cans + \" cans waiting\";\n    }\n\n    private int blocksReady() {\n        return this.cans / this.cansPerBlock;\n    }\n}\n","hints":["The first load of 90 fits. The second would make 180 cans, over 150, so `load` refuses it and the compactor keeps 90.","Each `press` makes one block of 40 cans and returns 40: 90 cans become 50, then 10. The same box as the lesson's class, and different answers."],"tests":[{"name":"Output","stdin":"","expect":"40\n40\n2 blocks, 10 cans waiting","hidden":false}],"require":[],"forbid":[],"lines":["40","40","2 blocks, 10 cans waiting"]},{"task":"The recycling center's truck driver wants to know how many kilos are still to be collected on a route. `Pickup.java` is ready, and you don't need to read it: its box says all you need.\n\n\n<figure class=\"uml\"><div class=\"uml-scroll\" tabindex=\"0\" role=\"group\" aria-label=\"Class diagram of Pickup\">\n<svg class=\"uml-svg\" viewBox=\"0 0 309 196\" width=\"309\" height=\"196\" style=\"width:19.32rem;min-width:17.71rem;aspect-ratio:309/196\" font-size=\"12\" aria-hidden=\"true\" focusable=\"false\"><rect class=\"u-bg\" fill=\"none\" x=\"6\" y=\"6\" width=\"297\" height=\"184\"/><rect class=\"u-head\" fill=\"none\" x=\"6\" y=\"6\" width=\"297\" height=\"24\"/><text x=\"154.5\" y=\"22\" text-anchor=\"middle\" class=\"u-name\">Pickup</text><text x=\"14\" y=\"46\">-address: String</text><text x=\"14\" y=\"62\">-kilos: double</text><text x=\"14\" y=\"78\">-done: boolean</text><text x=\"14\" y=\"102\">+Pickup(address: String, kilos: double)</text><text x=\"14\" y=\"118\">+getAddress(): String</text><text x=\"14\" y=\"134\">+getKilos(): double</text><text x=\"14\" y=\"150\">+isDone(): boolean</text><text x=\"14\" y=\"166\">+markDone(): void</text><text x=\"14\" y=\"182\">+toString(): String</text><path class=\"u-sep\" fill=\"none\" d=\"M6 30h297M6 86h297\"/><rect class=\"u-frame\" fill=\"none\" x=\"6\" y=\"6\" width=\"297\" height=\"184\"/></svg>\n</div><details class=\"uml-text\"><summary>The diagram as text</summary><ul><li><strong>Pickup</strong>, a class<ul><li>private field <code>address: String</code></li><li>private field <code>kilos: double</code></li><li>private field <code>done: boolean</code></li><li>public constructor <code>Pickup(address: String, kilos: double)</code></li><li>public method <code>getAddress(): String</code></li><li>public method <code>getKilos(): double</code></li><li>public method <code>isDone(): boolean</code></li><li>public method <code>markDone(): void</code></li><li>public method <code>toString(): String</code></li></ul></li></ul></details></figure>\n\n\nIn `Main.java`, write the method `public static double kilosLeft(ArrayList<Pickup> pickups)`, which returns the kilos of the pickups that aren't done yet, added up. The check runs:\n\n```java\nArrayList<Pickup> route = new ArrayList<>();\nroute.add(new Pickup(\"12 Mill Road\", 35.5));\nroute.add(new Pickup(\"4 Elm Street\", 20.0));\nroute.add(new Pickup(\"9 Quay Lane\", 12.25));\nroute.get(1).markDone();\nSystem.out.println(kilosLeft(route));\n```\n\nand expects:\n\n```\n47.75\n```\n","kind":"code","seed":"// ==== Main.java ====\nimport java.util.ArrayList;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Pickup> route = new ArrayList<>();\n        route.add(new Pickup(\"12 Mill Road\", 35.5));\n        route.add(new Pickup(\"4 Elm Street\", 20.0));\n        route.add(new Pickup(\"9 Quay Lane\", 12.25));\n        route.get(1).markDone();\n        System.out.println(kilosLeft(route));\n    }\n\n    // Write the method kilosLeft here.\n}\n\n// ==== Pickup.java ====\npublic class Pickup {\n    private String address;\n    private double kilos;\n    private boolean done;\n\n    public Pickup(String address, double kilos) {\n        this.address = address;\n        this.kilos = kilos;\n        this.done = false;\n    }\n\n    public String getAddress() {\n        return this.address;\n    }\n\n    public double getKilos() {\n        return this.kilos;\n    }\n\n    public boolean isDone() {\n        return this.done;\n    }\n\n    public void markDone() {\n        this.done = true;\n    }\n\n    @Override\n    public String toString() {\n        return this.address + \": \" + this.kilos + \" kg\";\n    }\n}\n","solution":"// ==== Main.java ====\nimport java.util.ArrayList;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Pickup> route = new ArrayList<>();\n        route.add(new Pickup(\"12 Mill Road\", 35.5));\n        route.add(new Pickup(\"4 Elm Street\", 20.0));\n        route.add(new Pickup(\"9 Quay Lane\", 12.25));\n        route.get(1).markDone();\n        System.out.println(kilosLeft(route));\n    }\n\n    public static double kilosLeft(ArrayList<Pickup> pickups) {\n        double total = 0;\n        for (Pickup pickup : pickups) {\n            if (!pickup.isDone()) {\n                total += pickup.getKilos();\n            }\n        }\n        return total;\n    }\n}\n\n// ==== Pickup.java ====\npublic class Pickup {\n    private String address;\n    private double kilos;\n    private boolean done;\n\n    public Pickup(String address, double kilos) {\n        this.address = address;\n        this.kilos = kilos;\n        this.done = false;\n    }\n\n    public String getAddress() {\n        return this.address;\n    }\n\n    public double getKilos() {\n        return this.kilos;\n    }\n\n    public boolean isDone() {\n        return this.done;\n    }\n\n    public void markDone() {\n        this.done = true;\n    }\n\n    @Override\n    public String toString() {\n        return this.address + \": \" + this.kilos + \" kg\";\n    }\n}\n","hints":["The box tells you what to call: `isDone()` gives a boolean and `getKilos()` a double. Start from `double total = 0;` and go through the list with a for-each loop.","Add a pickup's `getKilos()` to the total only `if (!pickup.isDone())`, and return the total after the loop."],"tests":[{"name":"Test 1","stdin":"","call":"ArrayList<Pickup> route = new ArrayList<>();\nroute.add(new Pickup(\"12 Mill Road\", 35.5));\nroute.add(new Pickup(\"4 Elm Street\", 20.0));\nroute.add(new Pickup(\"9 Quay Lane\", 12.25));\nroute.get(1).markDone();\nSystem.out.println(kilosLeft(route));\n","expect":"47.75","hidden":false},{"name":"Test 2","stdin":"","call":"ArrayList<Pickup> route = new ArrayList<>();\nSystem.out.println(kilosLeft(route));\nroute.add(new Pickup(\"1 Dock Road\", 8.5));\nroute.add(new Pickup(\"2 Dock Road\", 0.25));\nSystem.out.println(kilosLeft(route));\nroute.get(0).markDone();\nroute.get(1).markDone();\nSystem.out.println(kilosLeft(route));\n","expect":"0.0\n8.75\n0.0","hidden":true}],"require":[{"pattern":"\\bpublic\\s+static\\s+double\\s+kilosLeft\\s*\\(\\s*ArrayList<Pickup>\\s+\\w+\\s*\\)","message":"Write the method as `public static double kilosLeft(ArrayList<Pickup> pickups)`."}],"forbid":[]}]}