{"id":"exceptions-interfaces","slug":"exceptions-and-interfaces","title":"Exceptions and interfaces","text":"An interface lists the headers of methods (module 35), and a header can include `throws`. Then it says, for every class that implements the interface, which checked exceptions that method may throw.\n\n### Door codes\n\nThe doors of an office building open with a code typed on a keypad. Some doors have one fixed code; others check a file of codes that the office manager keeps up to date. The keypad doesn't care which: it needs something that can answer \"is this code valid?\". Reading a file can fail, and the interface says so:\n\n```java\nimport java.io.IOException;\n\npublic interface DoorCodes {\n    boolean isValid(String code) throws IOException;\n}\n```\n\nHere are two classes that implement it, and three doors:\n\n```file staff.txt\n4711\n2580\n```\n\n```java\nimport java.io.IOException;\n\npublic class Main {\n    public static void main(String[] args) {\n        open(\"Bike shed\", new FixedCode(\"1234\"), \"2580\");\n        open(\"Staff entrance\", new CodeFile(\"staff.txt\"), \"2580\");\n        open(\"Guest entrance\", new CodeFile(\"guests.txt\"), \"2580\");\n    }\n\n    public static void open(String door, DoorCodes codes, String typed) {\n        try {\n            if (codes.isValid(typed)) {\n                System.out.println(door + \": the door opens\");\n            } else {\n                System.out.println(door + \": wrong code\");\n            }\n        } catch (IOException e) {\n            System.out.println(door + \": out of order, can't read \" + e.getMessage());\n        }\n    }\n}\n// ==== DoorCodes.java ====\nimport java.io.IOException;\n\npublic interface DoorCodes {\n    boolean isValid(String code) throws IOException;\n}\n// ==== FixedCode.java ====\npublic class FixedCode implements DoorCodes {\n    private String code;\n\n    public FixedCode(String code) {\n        this.code = code;\n    }\n\n    @Override\n    public boolean isValid(String code) {\n        return this.code.equals(code);\n    }\n}\n// ==== CodeFile.java ====\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\n\npublic class CodeFile implements DoorCodes {\n    private String fileName;\n\n    public CodeFile(String fileName) {\n        this.fileName = fileName;\n    }\n\n    @Override\n    public boolean isValid(String code) throws IOException {\n        return Files.readAllLines(Paths.get(this.fileName)).contains(code);\n    }\n}\n```\n\n```output\nBike shed: wrong code\nStaff entrance: the door opens\nGuest entrance: out of order, can't read guests.txt\n```\n\n- CodeFile reads a file, which can throw an IOException, and its `isValid` passes it on with `throws IOException`, as the interface allows.\n- FixedCode can't fail, and its `isValid` has no `throws` at all. That's allowed: an implementation may throw fewer checked exceptions than the interface says, or none.\n- `open` gets a DoorCodes. All it knows is the interface's header, so it must be ready for the IOException, even when the object behind it happens to be a FixedCode.\n\n### What an implementation may throw\n\nThe interface is a promise to the code that uses it: `open` catches IOException because the interface says that's what can come. If an implementation could throw some other checked exception, `open` wouldn't be ready for it. So javac refuses an implementation that declares a checked exception the interface doesn't list, or a broader one:\n\n```java\nimport java.io.IOException;\n\npublic class Main {\n    public static void main(String[] args) {\n        DoorCodes codes = new CodeFile(\"staff.txt\");\n        try {\n            System.out.println(codes.isValid(\"2580\"));\n        } catch (IOException e) {\n            System.out.println(\"Out of order\");\n        }\n    }\n}\n// ==== DoorCodes.java ====\nimport java.io.IOException;\n\npublic interface DoorCodes {\n    boolean isValid(String code) throws IOException;\n}\n// ==== CodeFile.java ====\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\n\npublic class CodeFile implements DoorCodes {\n    private String fileName;\n\n    public CodeFile(String fileName) {\n        this.fileName = fileName;\n    }\n\n    @Override\n    public boolean isValid(String code) throws Exception {\n        return Files.readAllLines(Paths.get(this.fileName)).contains(code);\n    }\n}\n```\n\n```javac\nCodeFile.java:12: error: isValid(String) in CodeFile cannot implement isValid(String) in DoorCodes\n    public boolean isValid(String code) throws Exception {\n                   ^\n  overridden method does not throw Exception\n1 error\n```\n\n`Exception` is broader than `IOException`: it includes checked exceptions that `open` doesn't catch. In short:\n\n- An implementation may declare the interface's checked exceptions, or classes below them (such as `NoSuchFileException`), or leave them out.\n- It may not add other checked exceptions.\n- Unchecked exceptions are always allowed, since nobody has to declare or catch them. FixedCode's `isValid` could throw an IllegalArgumentException when the typed code is empty, and it still needs no `throws`.\n\nThe same rule holds for a method that overrides a method of a superclass (module 34).\n\n### The variable's type decides\n\nWhether a call needs a `try` depends on the header javac sees, and that's the header in the variable's type. Through a FixedCode variable, `isValid` throws nothing checked, so no `try` is needed:\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        FixedCode shed = new FixedCode(\"1234\");\n        System.out.println(shed.isValid(\"1234\"));\n    }\n}\n// ==== DoorCodes.java ====\nimport java.io.IOException;\n\npublic interface DoorCodes {\n    boolean isValid(String code) throws IOException;\n}\n// ==== FixedCode.java ====\npublic class FixedCode implements DoorCodes {\n    private String code;\n\n    public FixedCode(String code) {\n        this.code = code;\n    }\n\n    @Override\n    public boolean isValid(String code) {\n        return this.code.equals(code);\n    }\n}\n```\n\n```output\ntrue\n```\n\nThrough a DoorCodes variable, the same call on the same object doesn't compile without one:\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        DoorCodes shed = new FixedCode(\"1234\");\n        System.out.println(shed.isValid(\"1234\"));\n    }\n}\n// ==== DoorCodes.java ====\nimport java.io.IOException;\n\npublic interface DoorCodes {\n    boolean isValid(String code) throws IOException;\n}\n// ==== FixedCode.java ====\npublic class FixedCode implements DoorCodes {\n    private String code;\n\n    public FixedCode(String code) {\n        this.code = code;\n    }\n\n    @Override\n    public boolean isValid(String code) {\n        return this.code.equals(code);\n    }\n}\n```\n\n```javac\nMain.java:4: error: unreported exception IOException; must be caught or declared to be thrown\n        System.out.println(shed.isValid(\"1234\"));\n                                       ^\n1 error\n```\n\n### throws Exception, and AutoCloseable\n\nInterfaces often declare `throws Exception`, the widest promise: then each implementation may throw whatever it needs to. Java's own AutoCloseable from step 4 is one of them: its method is `void close() throws Exception`. The Faucet's `close()` left the `throws` out, since turning off a faucet can't fail. That's why its try-with-resources didn't need a `catch (Exception e)`: javac knew from the Faucet's own header that closing it throws nothing checked.\n","task":"A door can also keep a short list of codes in memory. `DoorCodes.java` is ready. In `CodeList.java`, write the class `CodeList`, which implements DoorCodes, with:\n\n- a constructor with no parameters; a new CodeList has no codes\n- `add(String code)`, which adds a code to the list\n- `isValid(String code)`, with `@Override`, which returns `true` if the code is on the list\n\nA list in memory can't fail to be read, so leave out the `throws`. `Main.java` calls `isValid` through a CodeList variable without a `try`, so it only compiles when CodeList's `isValid` throws nothing checked. The check runs:\n\n```java\nCodeList codes = new CodeList();\ncodes.add(\"1357\");\ncodes.add(\"8642\");\nSystem.out.println(codes.isValid(\"8642\"));\nSystem.out.println(codes.isValid(\"1234\"));\n```\n\nand expects:\n\n```\ntrue\nfalse\n```\n","kind":"code","seed":"// ==== CodeList.java ====\npublic class CodeList {\n\n}\n\n// ==== DoorCodes.java ====\nimport java.io.IOException;\n\npublic interface DoorCodes {\n    boolean isValid(String code) throws IOException;\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        CodeList codes = new CodeList();\n        codes.add(\"1357\");\n        codes.add(\"8642\");\n        System.out.println(codes.isValid(\"8642\"));\n        System.out.println(codes.isValid(\"1234\"));\n    }\n}\n","solution":"// ==== CodeList.java ====\nimport java.util.ArrayList;\n\npublic class CodeList implements DoorCodes {\n    private ArrayList<String> codes;\n\n    public CodeList() {\n        this.codes = new ArrayList<>();\n    }\n\n    public void add(String code) {\n        this.codes.add(code);\n    }\n\n    @Override\n    public boolean isValid(String code) {\n        return this.codes.contains(code);\n    }\n}\n\n// ==== DoorCodes.java ====\nimport java.io.IOException;\n\npublic interface DoorCodes {\n    boolean isValid(String code) throws IOException;\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        CodeList codes = new CodeList();\n        codes.add(\"1357\");\n        codes.add(\"8642\");\n        System.out.println(codes.isValid(\"8642\"));\n        System.out.println(codes.isValid(\"1234\"));\n    }\n}\n","hints":["Start with `public class CodeList implements DoorCodes {`, with an `ArrayList<String>` as the instance variable, created in the constructor. The class needs `import java.util.ArrayList;`.","The header is `public boolean isValid(String code)`, with no `throws`. A list's `contains` tells whether the code is on it."],"tests":[{"name":"Test 1","stdin":"","call":"CodeList codes = new CodeList();\ncodes.add(\"1357\");\ncodes.add(\"8642\");\nSystem.out.println(codes.isValid(\"8642\"));\nSystem.out.println(codes.isValid(\"1234\"));\n","expect":"true\nfalse","hidden":false},{"name":"Test 2","stdin":"","call":"DoorCodes door = new CodeList();\nSystem.out.println(door.isValid(\"1357\"));\n","expect":"false","hidden":true},{"name":"Test 3","stdin":"","call":"CodeList codes = new CodeList();\ncodes.add(\"0000\");\ncodes.add(\"4455\");\ncodes.add(\"9021\");\nSystem.out.println(codes.isValid(\"9021\") + \" \" + codes.isValid(\"0000\") + \" \" + codes.isValid(\"4456\"));\n","expect":"true true false","hidden":true}],"require":[{"pattern":"\\bclass\\s+CodeList\\s+implements\\s+DoorCodes\\b","message":"Write the header as `public class CodeList implements DoorCodes`."},{"pattern":"@Override","message":"Put `@Override` above `isValid`, so that javac checks its header against the interface's."}],"forbid":[],"more":[{"task":"This keypad locks itself after too many wrong codes. Its `isValid` throws no checked exception, but it may throw an unchecked one. What does the program print?\n","kind":"predict","seed":"import java.io.IOException;\n\npublic class Main {\n    public static void main(String[] args) {\n        DoorCodes codes = new LimitedCode(\"2468\", 2);\n        String[] tries = {\"1111\", \"2468\", \"3333\", \"2468\"};\n        for (String code : tries) {\n            try {\n                System.out.println(code + \": \" + codes.isValid(code));\n            } catch (IOException e) {\n                System.out.println(\"out of order\");\n            } catch (IllegalStateException e) {\n                System.out.println(e.getMessage());\n            }\n        }\n    }\n}\n// ==== DoorCodes.java ====\nimport java.io.IOException;\n\npublic interface DoorCodes {\n    boolean isValid(String code) throws IOException;\n}\n// ==== LimitedCode.java ====\npublic class LimitedCode implements DoorCodes {\n    private String code;\n    private int limit;\n    private int wrong;\n\n    public LimitedCode(String code, int limit) {\n        this.code = code;\n        this.limit = limit;\n    }\n\n    @Override\n    public boolean isValid(String code) {\n        if (this.wrong >= this.limit) {\n            throw new IllegalStateException(\"Locked after \" + this.limit + \" wrong codes\");\n        }\n        if (this.code.equals(code)) {\n            return true;\n        }\n        this.wrong++;\n        return false;\n    }\n}\n","solution":"import java.io.IOException;\n\npublic class Main {\n    public static void main(String[] args) {\n        DoorCodes codes = new LimitedCode(\"2468\", 2);\n        String[] tries = {\"1111\", \"2468\", \"3333\", \"2468\"};\n        for (String code : tries) {\n            try {\n                System.out.println(code + \": \" + codes.isValid(code));\n            } catch (IOException e) {\n                System.out.println(\"out of order\");\n            } catch (IllegalStateException e) {\n                System.out.println(e.getMessage());\n            }\n        }\n    }\n}\n// ==== DoorCodes.java ====\nimport java.io.IOException;\n\npublic interface DoorCodes {\n    boolean isValid(String code) throws IOException;\n}\n// ==== LimitedCode.java ====\npublic class LimitedCode implements DoorCodes {\n    private String code;\n    private int limit;\n    private int wrong;\n\n    public LimitedCode(String code, int limit) {\n        this.code = code;\n        this.limit = limit;\n    }\n\n    @Override\n    public boolean isValid(String code) {\n        if (this.wrong >= this.limit) {\n            throw new IllegalStateException(\"Locked after \" + this.limit + \" wrong codes\");\n        }\n        if (this.code.equals(code)) {\n            return true;\n        }\n        this.wrong++;\n        return false;\n    }\n}\n","hints":["Only wrong codes are counted: after `1111` and `3333` there are two. The right code in between returns `true` and changes nothing.","The fourth call finds two wrong codes already, and throws before it looks at the code. Its `println` never prints, and the IllegalStateException block prints the message. The IOException block never runs, but it has to be there, since `codes` is a DoorCodes."],"tests":[{"name":"Output","stdin":"","expect":"1111: false\n2468: true\n3333: false\nLocked after 2 wrong codes","hidden":false}],"require":[],"forbid":[],"lines":["1111: false","2468: true","3333: false","Locked after 2 wrong codes"]},{"task":"Another door's code changes every day: the first line of `today.txt` is today's code. `DailyCode.java` reads it with a Scanner in a try-with-resources without a `catch`, so that its `isValid` passes the IOException on. The program reads a typed code and prints `The door opens` or `Wrong code`, but it doesn't compile. Fix it:\n\n- DailyCode's `isValid` declares more than DoorCodes allows. Make it declare what the interface says.\n- Then `main` has to deal with the exception: when the code can't be read, the program prints `Keypad out of order`.\n\nFor the input `7294` and the file shown below, the program prints:\n\n```\nThe door opens\n```\n","kind":"code","seed":"// ==== DailyCode.java ====\nimport java.io.IOException;\nimport java.nio.file.Paths;\nimport java.util.Scanner;\n\npublic class DailyCode implements DoorCodes {\n    private String fileName;\n\n    public DailyCode(String fileName) {\n        this.fileName = fileName;\n    }\n\n    @Override\n    public boolean isValid(String code) throws Exception {\n        try (Scanner scanner = new Scanner(Paths.get(this.fileName))) {\n            return scanner.nextLine().equals(code);\n        }\n    }\n}\n\n// ==== Main.java ====\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        String typed = scanner.nextLine();\n        DoorCodes codes = new DailyCode(\"today.txt\");\n        if (codes.isValid(typed)) {\n            System.out.println(\"The door opens\");\n        } else {\n            System.out.println(\"Wrong code\");\n        }\n    }\n}\n\n// ==== DoorCodes.java ====\nimport java.io.IOException;\n\npublic interface DoorCodes {\n    boolean isValid(String code) throws IOException;\n}\n","solution":"// ==== DailyCode.java ====\nimport java.io.IOException;\nimport java.nio.file.Paths;\nimport java.util.Scanner;\n\npublic class DailyCode implements DoorCodes {\n    private String fileName;\n\n    public DailyCode(String fileName) {\n        this.fileName = fileName;\n    }\n\n    @Override\n    public boolean isValid(String code) throws IOException {\n        try (Scanner scanner = new Scanner(Paths.get(this.fileName))) {\n            return scanner.nextLine().equals(code);\n        }\n    }\n}\n\n// ==== Main.java ====\nimport java.io.IOException;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        String typed = scanner.nextLine();\n        DoorCodes codes = new DailyCode(\"today.txt\");\n        try {\n            if (codes.isValid(typed)) {\n                System.out.println(\"The door opens\");\n            } else {\n                System.out.println(\"Wrong code\");\n            }\n        } catch (IOException e) {\n            System.out.println(\"Keypad out of order\");\n        }\n    }\n}\n\n// ==== DoorCodes.java ====\nimport java.io.IOException;\n\npublic interface DoorCodes {\n    boolean isValid(String code) throws IOException;\n}\n","hints":["javac's first message is about DailyCode: `overridden method does not throw Exception`. The interface allows `IOException`, which DailyCode already imports.","Next javac says `unreported exception IOException` in `main`. Put the `if` and its `else` in a `try` block, and print `Keypad out of order` in `catch (IOException e)`, which needs `import java.io.IOException;` in Main.java."],"tests":[{"name":"Test 1","stdin":"7294\n","files":{"today.txt":"7294\n"},"expect":"The door opens","hidden":false},{"name":"Test 2","stdin":"1111\n","files":{"today.txt":"7294\n"},"expect":"Wrong code","hidden":false},{"name":"Without the file","stdin":"7294\n","expect":"Keypad out of order","hidden":true},{"name":"Test 4","stdin":"3108\n","files":{"today.txt":"3108\n"},"expect":"The door opens","hidden":true}],"require":[{"pattern":"\\bisValid\\s*\\(\\s*String\\s+\\w+\\s*\\)\\s*throws\\s+IOException\\b","message":"DailyCode's `isValid` should declare `throws IOException`, as the interface does."}],"forbid":[]}]}