{"id":"exceptions-resources","slug":"try-with-resources","title":"Exceptions and resources","text":"Module 20 read files with a Scanner in `try (...)`, and said that this form of `try` closes the file. This step looks at what that means, and when it happens.\n\n### Resources\n\nAn open file is a **resource**: something a program borrows from the operating system while it uses it, and gives back when it's done, by **closing** it. Until then the system keeps the file marked as in use. On some systems another program can't change or delete a file while it's open, and a program that opens files without closing them can run out of files it's allowed to have open at once. Everything a program has open is closed when it ends, but some programs, such as a web server, run for months.\n\nA Scanner that reads a file has a method `close()`, and try-with-resources calls it for you:\n\n```java\ntry (Scanner scanner = new Scanner(Paths.get(\"settings.txt\"))) {\n    // read with the scanner\n} catch (Exception e) {\n    // the reading failed\n}\n```\n\n- The **resource** is created in the parentheses after `try`. It exists only inside the `try` block.\n- When the `try` block ends, Java calls the resource's `close()`, however the block ends: after its last line, with a `return`, or with an exception.\n- When an exception comes out of the `try` block, the resource is closed first, and then the `catch` block runs.\n- When creating the resource fails, for example because there's no such file, there's no Scanner to close, and Java goes straight to the `catch` block.\n- A try-with-resources needs no `catch` block at all when its method passes the exception on with `throws IOException`. The file is closed all the same, and the exception goes on to the caller.\n\n### Seeing it happen\n\nClosing a Scanner prints nothing, so here's a class whose `close()` does. An object can be a resource when its class implements Java's interface `AutoCloseable`, which has one method, `close()`. The Scanner's class implements it, and so does this faucet, which turns the water on when it's created and off when it's closed:\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        try (Faucet faucet = new Faucet(\"kitchen\")) {\n            System.out.println(\"Filling the kettle\");\n            int cups = Integer.parseInt(\"four\");\n            System.out.println(\"Filled \" + cups + \" cups\");\n        } catch (NumberFormatException e) {\n            System.out.println(\"Error: \" + e.getMessage());\n        }\n        System.out.println(\"Done\");\n    }\n}\n// ==== Faucet.java ====\npublic class Faucet implements AutoCloseable {\n    private String room;\n\n    public Faucet(String room) {\n        this.room = room;\n        System.out.println(\"Water on in the \" + room);\n    }\n\n    @Override\n    public void close() {\n        System.out.println(\"Water off in the \" + this.room);\n    }\n}\n```\n\n```output\nWater on in the kitchen\nFilling the kettle\nWater off in the kitchen\nError: For input string: \"four\"\nDone\n```\n\nThe water goes off before the `catch` block runs: the resource is closed as soon as the `try` block ends. (You won't need resources of your own in this course: Java's own, such as the Scanner, already implement AutoCloseable.)\n\nSeveral resources can go in the parentheses, separated by semicolons. They're closed in the opposite order: the one created last is closed first.\n\n### Returning from inside\n\nBecause the resource is closed however the block ends, a method can `return` from the middle of a try-with-resources. This one returns the first line of a file that starts with a given text. When it finds the line, it returns at once, and the file is closed on the way out:\n\n```file settings.txt\nvolume=7\ntheme=dark\n```\n\n```java\nimport java.nio.file.Paths;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        System.out.println(findLine(\"settings.txt\", \"theme\"));\n        System.out.println(findLine(\"settings.txt\", \"language\"));\n        System.out.println(findLine(\"colors.txt\", \"theme\"));\n    }\n\n    public static String findLine(String fileName, String start) {\n        try (Scanner scanner = new Scanner(Paths.get(fileName))) {\n            while (scanner.hasNextLine()) {\n                String line = scanner.nextLine();\n                if (line.startsWith(start)) {\n                    return line;\n                }\n            }\n        } catch (Exception e) {\n            return \"no file \" + fileName;\n        }\n        return \"none\";\n    }\n}\n```\n\n```output\ntheme=dark\nnone\nno file colors.txt\n```\n\n### The long way\n\nBefore try-with-resources came to Java (in version 7), programs closed their files themselves, in a `finally` block, so that it happened even after an exception:\n\n```java\nScanner scanner = new Scanner(Paths.get(\"settings.txt\"));\ntry {\n    while (scanner.hasNextLine()) {\n        System.out.println(scanner.nextLine());\n    }\n} finally {\n    scanner.close();\n}\n```\n\nYou'll still see this in older code. try-with-resources does the same with less to write, and nothing to forget.\n\n### Not the keyboard\n\nOne Scanner never goes in a try-with-resources: `new Scanner(System.in)`. Closing it closes `System.in` too, and after that the program can't read the keyboard any more, not even with a new Scanner. The keyboard isn't a file the program borrowed, so leave that Scanner open.\n","task":"This program reads water meter readings from `meter.txt`, one whole number per line, and prints how much water was used: the last reading minus the first. It works, but it never closes the file. Make the Scanner a resource of the `try`, so that the file is closed when the reading ends. For the file shown below, it prints:\n\n```\nUsed: 37 liters\n```\n","kind":"code","seed":"import java.nio.file.Paths;\nimport java.util.ArrayList;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Integer> readings = new ArrayList<>();\n        try {\n            Scanner scanner = new Scanner(Paths.get(\"meter.txt\"));\n            while (scanner.hasNextLine()) {\n                readings.add(Integer.parseInt(scanner.nextLine()));\n            }\n        } catch (Exception e) {\n            System.out.println(\"Error: \" + e.getMessage());\n        }\n        int used = readings.get(readings.size() - 1) - readings.get(0);\n        System.out.println(\"Used: \" + used + \" liters\");\n    }\n}\n","solution":"import java.nio.file.Paths;\nimport java.util.ArrayList;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Integer> readings = new ArrayList<>();\n        try (Scanner scanner = new Scanner(Paths.get(\"meter.txt\"))) {\n            while (scanner.hasNextLine()) {\n                readings.add(Integer.parseInt(scanner.nextLine()));\n            }\n        } catch (Exception e) {\n            System.out.println(\"Error: \" + e.getMessage());\n        }\n        int used = readings.get(readings.size() - 1) - readings.get(0);\n        System.out.println(\"Used: \" + used + \" liters\");\n    }\n}\n","hints":["Module 20, and the `findLine` example above, create the Scanner in the parentheses right after `try`. Do the same with this Scanner.","Move the Scanner line into `try (...)`, without its semicolon: `try (Scanner scanner = new Scanner(Paths.get(\"meter.txt\"))) {`. The loop stays inside the `try` block, and the `catch` block stays as it is."],"tests":[{"name":"Test 1","stdin":"","files":{"meter.txt":"1208\n1219\n1245\n"},"expect":"Used: 37 liters","hidden":false},{"name":"Test 2","stdin":"","files":{"meter.txt":"40210\n40215\n40233\n40290\n40302\n"},"expect":"Used: 92 liters","hidden":true}],"require":[{"pattern":"\\btry\\s*\\(\\s*Scanner\\s+\\w+\\s*=\\s*new\\s+Scanner\\s*\\(","message":"Create the Scanner in the parentheses after `try`."}],"forbid":[],"more":[{"task":"Here's a faucet that prints a word when it's turned on and off. The bath is filled with two of them, as two resources of one `try`. What does the program print?\n","kind":"predict","seed":"public class Main {\n    public static void main(String[] args) {\n        try (Faucet hot = new Faucet(\"hot\"); Faucet cold = new Faucet(\"cold\")) {\n            System.out.println(\"filling\");\n            int level = 10 / 0;\n            System.out.println(\"level \" + level);\n        } catch (ArithmeticException e) {\n            System.out.println(\"caught\");\n        } finally {\n            System.out.println(\"towel\");\n        }\n    }\n}\n// ==== Faucet.java ====\npublic class Faucet implements AutoCloseable {\n    private String name;\n\n    public Faucet(String name) {\n        this.name = name;\n        System.out.println(name + \" on\");\n    }\n\n    @Override\n    public void close() {\n        System.out.println(this.name + \" off\");\n    }\n}\n","solution":"public class Main {\n    public static void main(String[] args) {\n        try (Faucet hot = new Faucet(\"hot\"); Faucet cold = new Faucet(\"cold\")) {\n            System.out.println(\"filling\");\n            int level = 10 / 0;\n            System.out.println(\"level \" + level);\n        } catch (ArithmeticException e) {\n            System.out.println(\"caught\");\n        } finally {\n            System.out.println(\"towel\");\n        }\n    }\n}\n// ==== Faucet.java ====\npublic class Faucet implements AutoCloseable {\n    private String name;\n\n    public Faucet(String name) {\n        this.name = name;\n        System.out.println(name + \" on\");\n    }\n\n    @Override\n    public void close() {\n        System.out.println(this.name + \" off\");\n    }\n}\n","hints":["The resources are created from left to right, and closed the other way around: the one created last is closed first.","They're closed as soon as the `try` block ends, before the `catch` block runs. The `finally` block comes last."],"tests":[{"name":"Output","stdin":"","expect":"hot on\ncold on\nfilling\ncold off\nhot off\ncaught\ntowel","hidden":false}],"require":[],"forbid":[],"lines":["hot on","cold on","filling","cold off","hot off","caught","towel"]},{"task":"Settings files often have comment lines, which start with `#`, and empty lines. Write the method `countSettings(String fileName)`, which returns how many lines of the file are settings: lines that aren't empty and don't start with `#`. When the file can't be read, it returns -1. Read the file with a Scanner in a try-with-resources. The check runs `System.out.println(countSettings(\"settings.txt\"));` with the file shown below, and expects:\n\n```\n2\n```\n","kind":"code","seed":"import java.nio.file.Paths;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        System.out.println(countSettings(\"settings.txt\"));\n    }\n\n    public static int countSettings(String fileName) {\n        return 0;\n    }\n}\n","solution":"import java.nio.file.Paths;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        System.out.println(countSettings(\"settings.txt\"));\n    }\n\n    public static int countSettings(String fileName) {\n        int count = 0;\n        try (Scanner scanner = new Scanner(Paths.get(fileName))) {\n            while (scanner.hasNextLine()) {\n                String line = scanner.nextLine();\n                if (!line.isEmpty() && !line.startsWith(\"#\")) {\n                    count++;\n                }\n            }\n        } catch (Exception e) {\n            return -1;\n        }\n        return count;\n    }\n}\n","hints":["Make a counter before the `try`, count the lines that are settings inside the loop, and return it after the whole `try` and `catch`.","The `catch` block returns -1. A line is a setting when `!line.isEmpty() && !line.startsWith(\"#\")`."],"tests":[{"name":"System.out.println(countSettings(\"settings.txt\"));","stdin":"","call":"System.out.println(countSettings(\"settings.txt\"));\n","files":{"settings.txt":"# photo app\nvolume=7\n\n# colors\ntheme=dark\n"},"expect":"2","hidden":false},{"name":"System.out.println(countSettings(\"prefs.txt\"));","stdin":"","call":"System.out.println(countSettings(\"prefs.txt\"));\n","files":{"prefs.txt":"language=fi\nfont=large\n# zoom=2\nsound=off\nautosave=on\n"},"expect":"4","hidden":true},{"name":"System.out.println(countSettings(\"missing.txt\"));","stdin":"","call":"System.out.println(countSettings(\"missing.txt\"));\n","expect":"-1","hidden":true},{"name":"System.out.println(countSettings(\"empty.txt\"));","stdin":"","call":"System.out.println(countSettings(\"empty.txt\"));\n","files":{"empty.txt":"# nothing set yet\n"},"expect":"0","hidden":true}],"require":[{"pattern":"\\btry\\s*\\(\\s*Scanner\\s+\\w+\\s*=\\s*new\\s+Scanner\\s*\\(","message":"Read the file with a Scanner created in the parentheses after `try`."}],"forbid":[]}]}