{"id":"reading-files-errors","slug":"when-the-file-is-missing","title":"When the file is missing","text":"A program that reads a file depends on something outside itself: the file might not be there, it might have another name, or it might be in another folder. Java knows this, and it doesn't even compile code that opens a file without saying what to do if that fails:\n\n```java\nimport java.nio.file.Paths;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(Paths.get(\"notes.txt\"));\n        while (scanner.hasNextLine()) {\n            System.out.println(scanner.nextLine());\n        }\n    }\n}\n```\n\n```javac\nMain.java:6: error: unreported exception IOException; must be caught or declared to be thrown\n        Scanner scanner = new Scanner(Paths.get(\"notes.txt\"));\n                          ^\n1 error\n```\n\nAn `IOException` is a failure in reading or writing data (I/O is short for input and output). Most exceptions, such as the `NumberFormatException` from module 16, can happen without warning; this kind is one that Java makes you plan for. `catch` is the plan. (The other option in the message, declaring it, comes later in the course.)\n\n### try and catch\n\nThe `try` block holds the code that might fail. If a line in it throws an exception, Java leaves the `try` block right there and runs the `catch` block, instead of crashing. After the `catch` block, the program goes on as usual. Here there's no file `prices.txt` at all:\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(\"Reading the prices...\");\n        try (Scanner scanner = new Scanner(Paths.get(\"prices.txt\"))) {\n            while (scanner.hasNextLine()) {\n                System.out.println(scanner.nextLine());\n            }\n            System.out.println(\"All prices read\");\n        } catch (Exception e) {\n            System.out.println(\"Error: \" + e.getMessage());\n        }\n        System.out.println(\"Bye!\");\n    }\n}\n```\n\n```output\nReading the prices...\nError: prices.txt\nBye!\n```\n\n- `catch (Exception e)` catches any exception. `e` is a variable that holds the exception, and `e.getMessage()` is its message. A missing file throws a `NoSuchFileException`, whose message is just the file's name: that's why the program prints `Error: prices.txt`. Your own text in the `catch` block, such as `Could not open prices.txt`, can say more.\n- `All prices read` isn't printed: the rest of the `try` block is skipped.\n- `Bye!` is printed: after the `catch` block, the program carries on.\n\n### A message instead of a crash\n\n`catch (Exception e)` catches every exception thrown inside its `try` block, not only the file's. A `try` without parentheses works for code that opens nothing:\n\n```java\ntry {\n    int number = Integer.valueOf(\"12a\");\n    System.out.println(\"Got \" + number);\n} catch (Exception e) {\n    System.out.println(\"Error: \" + e.getMessage());\n}\nSystem.out.println(\"Still running\");\n```\n\n```output\nError: For input string: \"12a\"\nStill running\n```\n\nWithout the `try`, the same line would crash the program with a `NumberFormatException`, as in module 16: Java's report, and nothing after it runs. With `catch`, your program decides what to say and keeps going.\n","task":"Fill in the blanks. The program prints the lines of `menu.txt`. When the file can't be read, it prints `Could not read the file: ` and the error's message instead, so without the file it prints `Could not read the file: menu.txt` (one of the tests gives no file). For the file shown below, it prints:\n\n```\ntomato soup\npasta\napple pie\n```\n","kind":"fill","seed":"import java.nio.file.Paths;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        try (Scanner scanner = new Scanner(Paths.get(\"menu.txt\"))) {\n            while (scanner.hasNextLine()) {\n                System.out.println(scanner.nextLine());\n            }\n        } [[catch]] (Exception e) {\n            System.out.println(\"Could not read the file: \" + e.[[getMessage]]());\n        }\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        try (Scanner scanner = new Scanner(Paths.get(\"menu.txt\"))) {\n            while (scanner.hasNextLine()) {\n                System.out.println(scanner.nextLine());\n            }\n        } catch (Exception e) {\n            System.out.println(\"Could not read the file: \" + e.getMessage());\n        }\n    }\n}\n","hints":["The block that runs when something goes wrong starts with `catch`.","The exception's message comes from `e.getMessage()`."],"tests":[{"name":"With the file","stdin":"","files":{"menu.txt":"tomato soup\npasta\napple pie\n"},"expect":"tomato soup\npasta\napple pie","hidden":false},{"name":"Without the file","stdin":"","expect":"Could not read the file: menu.txt","hidden":false},{"name":"Another menu","stdin":"","files":{"menu.txt":"pancakes\nfruit salad\n"},"expect":"pancakes\nfruit salad","hidden":true}],"require":[],"forbid":[],"more":[{"task":"The file `visitors.txt` has a line for each visitor of a museum. Print how many visitors there were, as `Visitors: ` and the number. If the file can't be read, print only `No visitor data`. For the file shown below, the program prints:\n\n```\nVisitors: 4\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\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        int count = 0;\n        try (Scanner scanner = new Scanner(Paths.get(\"visitors.txt\"))) {\n            while (scanner.hasNextLine()) {\n                scanner.nextLine();\n                count++;\n            }\n            System.out.println(\"Visitors: \" + count);\n        } catch (Exception e) {\n            System.out.println(\"No visitor data\");\n        }\n    }\n}\n","hints":["Count in the loop, and call `scanner.nextLine();` in every round even though the line isn't used: without it, the loop never moves on.","Print the count at the end of the `try` block, not after the whole `try`/`catch`: then it's skipped when the file can't be read, and only the `catch` block's message is printed."],"tests":[{"name":"Test 1","stdin":"","files":{"visitors.txt":"Hanna Virtanen\nLuis Ortega\nAmara Obi\nJin Park\n"},"expect":"Visitors: 4","hidden":false},{"name":"Without the file","stdin":"","expect":"No visitor data","hidden":false},{"name":"Test 3","stdin":"","files":{"visitors.txt":"Visitor 1\nVisitor 2\nVisitor 3\nVisitor 4\nVisitor 5\nVisitor 6\nVisitor 7\n"},"expect":"Visitors: 7","hidden":true},{"name":"Test 4","stdin":"","files":{"visitors.txt":"Nobody else came\n"},"expect":"Visitors: 1","hidden":true}],"require":[],"forbid":[]},{"task":"What does this program print? Follow it into the `catch` block, and out again.\n","kind":"predict","seed":"public class Main {\n    public static void main(String[] args) {\n        String[] values = {\"12\", \"7\", \"x\", \"3\"};\n        int sum = 0;\n        try {\n            for (String value : values) {\n                sum += Integer.valueOf(value);\n                System.out.println(\"Sum so far: \" + sum);\n            }\n            System.out.println(\"All added\");\n        } catch (Exception e) {\n            System.out.println(\"Error: \" + e.getMessage());\n        }\n        System.out.println(\"Total: \" + sum);\n    }\n}\n","solution":"public class Main {\n    public static void main(String[] args) {\n        String[] values = {\"12\", \"7\", \"x\", \"3\"};\n        int sum = 0;\n        try {\n            for (String value : values) {\n                sum += Integer.valueOf(value);\n                System.out.println(\"Sum so far: \" + sum);\n            }\n            System.out.println(\"All added\");\n        } catch (Exception e) {\n            System.out.println(\"Error: \" + e.getMessage());\n        }\n        System.out.println(\"Total: \" + sum);\n    }\n}\n","hints":["`Integer.valueOf(\"x\")` throws a `NumberFormatException` with the message `For input string: \"x\"`. The loop and the rest of the `try` block stop there.","`3` is never added, and `All added` is skipped. After the `catch` block, the last line prints the sum as it was."],"tests":[{"name":"Output","stdin":"","expect":"Sum so far: 12\nSum so far: 19\nError: For input string: \"x\"\nTotal: 19","hidden":false}],"require":[],"forbid":[],"lines":["Sum so far: 12","Sum so far: 19","Error: For input string: \"x\"","Total: 19"]}]}