{"id":"switch-and-text-var","slug":"var","title":"var for local variables","text":"Apart from lambda parameters (module 37), every variable in this course has had its type written in front of its name. Since Java 10, a local variable (one declared inside a method) can be declared with `var` instead, and javac works out its type from the value it's given:\n\n```java\nvar name = \"Ada\";\nvar age = 36;\nvar height = 1.65;\nvar languages = new ArrayList<String>();\nlanguages.add(\"Java\");\nSystem.out.println(name.length() + age + \" \" + height + \" \" + languages);\n```\n\n```output\n39 1.65 [Java]\n```\n\n`name` is a String, `age` an int, `height` a double and `languages` an `ArrayList<String>`, exactly as if the types were written out. `var` isn't a type of its own, and it doesn't make Java a language where a variable can hold anything: the type is decided once, when the variable is declared, and stays.\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        var count = 0;\n        count = \"many\";\n        System.out.println(count);\n    }\n}\n```\n\n```javac\nMain.java:4: error: incompatible types: String cannot be converted to int\n        count = \"many\";\n                ^\n1 error\n```\n\n### Where var helps\n\n`var` is at its best when the type is long and the right-hand side already shows it:\n\n```java\nHashMap<String, ArrayList<Integer>> scores = new HashMap<String, ArrayList<Integer>>();\nvar scores = new HashMap<String, ArrayList<Integer>>();\n```\n\nBoth lines declare the same variable; the second says the type once. Note that the type arguments move to the right: `var scores = new HashMap<>();` would give javac nothing to work them out from, and it makes a `HashMap<Object, Object>`.\n\nWhere the right-hand side doesn't show the type, `var` makes code harder to read: in `var result = calculate(data);`, the reader has to look up `calculate` to know what `result` is. Many teams use `var` only when the type is plain to see.\n\n### Where var isn't allowed\n\njavac must be able to work out the type from the declaration itself, so `var` needs a value right away, and `null` doesn't say which type is meant:\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        var total;\n        var best = null;\n        System.out.println(\"Done\");\n    }\n}\n```\n\n```javac\nMain.java:3: error: cannot infer type for local variable total\n        var total;\n            ^\n  (cannot use 'var' on variable without initializer)\nMain.java:4: error: cannot infer type for local variable best\n        var best = null;\n            ^\n  (variable initializer is 'null')\n2 errors\n```\n\n`var` is only for local variables (the loop variables of `for` included) and a lambda's parameters. Instance and static variables, method parameters and return types still need their types written out: javac answers a `var` there with \"'var' is not allowed here\".\n\n### var in loops, and a map's entries\n\nA for-each loop's variable can be `var` too. That's handy for going through a map. So far, the course went through a map's keys with `keySet()` and looked up each value with `get`. A map's `entrySet()` gives its **entries** instead, each a key and its value together, with `getKey()` and `getValue()`. An entry's type is `Map.Entry<String, Integer>` here, a mouthful that `var` saves you from writing. A `TreeMap`, which module 31 mentioned, keeps its keys sorted, so the loop goes through them in alphabetical order:\n\n```java\nimport java.util.TreeMap;\n\npublic class Main {\n    public static void main(String[] args) {\n        var stock = new TreeMap<String, Integer>();\n        stock.put(\"water\", 12);\n        stock.put(\"apple\", 4);\n        stock.put(\"chips\", 0);\n        for (var entry : stock.entrySet()) {\n            if (entry.getValue() == 0) {\n                System.out.println(entry.getKey() + \": sold out\");\n            } else {\n                System.out.println(entry.getKey() + \": \" + entry.getValue());\n            }\n        }\n    }\n}\n```\n\n```output\napple: 4\nchips: sold out\nwater: 12\n```\n","task":"A dice tournament reads rolls, one per line as a player's name and the roll, such as `Noor 5`, until the line `end`, and prints each player's total, in the order the players first rolled. The program works, but its types make it wordy. Declare every local variable with `var` instead of its type: the ones inside the loops and the loops' own variables too. What it prints stays the same. With this input:\n\n```input\nNoor 5\nElif 6\nNoor 3\nElif 6\nend\n```\n\nthe program prints:\n\n```\nNoor: 8\nElif: 12\n```\n","kind":"code","seed":"import java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        ArrayList<String> players = new ArrayList<String>();\n        HashMap<String, ArrayList<Integer>> rolls = new HashMap<String, ArrayList<Integer>>();\n        while (true) {\n            String line = scanner.nextLine();\n            if (line.equals(\"end\")) {\n                break;\n            }\n            String[] parts = line.split(\" \");\n            String player = parts[0];\n            if (!rolls.containsKey(player)) {\n                players.add(player);\n                rolls.put(player, new ArrayList<Integer>());\n            }\n            rolls.get(player).add(Integer.valueOf(parts[1]));\n        }\n        for (String player : players) {\n            int total = 0;\n            for (int roll : rolls.get(player)) {\n                total += roll;\n            }\n            System.out.println(player + \": \" + total);\n        }\n    }\n}\n","solution":"import java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        var scanner = new Scanner(System.in);\n        var players = new ArrayList<String>();\n        var rolls = new HashMap<String, ArrayList<Integer>>();\n        while (true) {\n            var line = scanner.nextLine();\n            if (line.equals(\"end\")) {\n                break;\n            }\n            var parts = line.split(\" \");\n            var player = parts[0];\n            if (!rolls.containsKey(player)) {\n                players.add(player);\n                rolls.put(player, new ArrayList<Integer>());\n            }\n            rolls.get(player).add(Integer.valueOf(parts[1]));\n        }\n        for (var player : players) {\n            var total = 0;\n            for (var roll : rolls.get(player)) {\n                total += roll;\n            }\n            System.out.println(player + \": \" + total);\n        }\n    }\n}\n","hints":["Each declaration loses its type and gets `var`: `var line = scanner.nextLine();`. In the loops too: `for (var player : players)`.","When the right-hand side is `new ArrayList<String>()`, keep the type argument there: `var players = new ArrayList<String>();`. With `<>`, javac couldn't tell what the list holds."],"tests":[{"name":"Test 1","stdin":"Noor 5\nElif 6\nNoor 3\nElif 6\nend\n","expect":"Noor: 8\nElif: 12","hidden":false},{"name":"Test 2","stdin":"Tomas 2\nInes 4\nRafa 1\nInes 3\nTomas 6\nTomas 1\nend\n","expect":"Tomas: 9\nInes: 7\nRafa: 1","hidden":true},{"name":"Test 3","stdin":"Solo 4\nend\n","expect":"Solo: 4","hidden":true}],"require":[{"pattern":"\\bvar\\b","min":9,"message":"Declare all nine local variables with `var`: scanner, players, rolls, line, parts, both player variables, total and roll."}],"forbid":[{"pattern":"\\b(Scanner|ArrayList\\s*<[^>]*>|HashMap\\s*<.*>|String(\\s*\\[\\s*\\])?|int)\\s+\\w+\\s*[=:]","message":"A local variable still has its type written out. Use `var` for every one of them."}],"more":[{"task":"A dice game reads rolls, one per line as a name and the roll, such as `Ada 4`, until the line `end`, and prints the winner: the first player with the highest roll. Someone wrote it with `var` everywhere, and now it doesn't compile. Press Run to see javac's errors and fix each line it names, then run again: javac names more lines once the first ones are fixed. Keep going until the program works. With this input:\n\n```input\nAda 4\nBo 6\nCy 6\nend\n```\n\nthe program prints:\n\n```\nBo wins with 6\n```\n","kind":"code","seed":"import java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        var scanner = new Scanner(System.in);\n        var highest;\n        var winner = null;\n        while (true) {\n            var line = scanner.nextLine();\n            if (line.equals(\"end\")) {\n                break;\n            }\n            var parts = line.split(\" \");\n            var roll = Integer.valueOf(parts[1]);\n            if (winner == null || roll > highest) {\n                highest = roll;\n                winner = parts[0];\n            }\n        }\n        announce(winner, highest);\n    }\n\n    public static void announce(var name, var roll) {\n        System.out.println(name + \" wins with \" + roll);\n    }\n}\n","solution":"import java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        var scanner = new Scanner(System.in);\n        var highest = 0;\n        String winner = null;\n        while (true) {\n            var line = scanner.nextLine();\n            if (line.equals(\"end\")) {\n                break;\n            }\n            var parts = line.split(\" \");\n            var roll = Integer.valueOf(parts[1]);\n            if (winner == null || roll > highest) {\n                highest = roll;\n                winner = parts[0];\n            }\n        }\n        announce(winner, highest);\n    }\n\n    public static void announce(String name, int roll) {\n        System.out.println(name + \" wins with \" + roll);\n    }\n}\n","hints":["A method's parameters can't be `var` at all: give `announce` the parameters `String name, int roll`.","`var highest;` has no value to work out a type from: give it one, `var highest = 0;`, or write its type, `int highest = 0;`. And `null` doesn't say which type `winner` is: write `String winner = null;`."],"tests":[{"name":"Test 1","stdin":"Ada 4\nBo 6\nCy 6\nend\n","expect":"Bo wins with 6","hidden":false},{"name":"Test 2","stdin":"Eve 2\nFinn 1\nGus 5\nHal 3\nend\n","expect":"Gus wins with 5","hidden":true},{"name":"Test 3","stdin":"Ivy 1\nend\n","expect":"Ivy wins with 1","hidden":true}],"require":[],"forbid":[]},{"task":"A board game club checks its dice by counting how often each face comes up. The program reads rolls, one whole number per line, until the line `end`, and counts them in a `TreeMap`. Write the loop that prints each face that came up and its count, like `3: 2`, smallest face first. Go through the map's `entrySet()` with a `var` loop variable. With this input:\n\n```input\n6\n3\n6\n1\n3\n6\nend\n```\n\nthe program prints:\n\n```\n1: 1\n3: 2\n6: 3\n```\n","kind":"code","seed":"import java.util.Scanner;\nimport java.util.TreeMap;\n\npublic class Main {\n    public static void main(String[] args) {\n        var scanner = new Scanner(System.in);\n        var counts = new TreeMap<Integer, Integer>();\n        while (true) {\n            var line = scanner.nextLine();\n            if (line.equals(\"end\")) {\n                break;\n            }\n            var face = Integer.valueOf(line);\n            counts.put(face, counts.getOrDefault(face, 0) + 1);\n        }\n        // print each face and its count\n\n    }\n}\n","solution":"import java.util.Scanner;\nimport java.util.TreeMap;\n\npublic class Main {\n    public static void main(String[] args) {\n        var scanner = new Scanner(System.in);\n        var counts = new TreeMap<Integer, Integer>();\n        while (true) {\n            var line = scanner.nextLine();\n            if (line.equals(\"end\")) {\n                break;\n            }\n            var face = Integer.valueOf(line);\n            counts.put(face, counts.getOrDefault(face, 0) + 1);\n        }\n        for (var entry : counts.entrySet()) {\n            System.out.println(entry.getKey() + \": \" + entry.getValue());\n        }\n    }\n}\n","hints":["`for (var entry : counts.entrySet()) {` goes through the entries, smallest key first, since a TreeMap keeps its keys sorted.","Each entry has `getKey()`, the face, and `getValue()`, its count."],"tests":[{"name":"Test 1","stdin":"6\n3\n6\n1\n3\n6\nend\n","expect":"1: 1\n3: 2\n6: 3","hidden":false},{"name":"Test 2","stdin":"2\n2\n5\n4\n2\nend\n","expect":"2: 3\n4: 1\n5: 1","hidden":true},{"name":"Test 3","stdin":"4\nend\n","expect":"4: 1","hidden":true}],"require":[{"pattern":"for\\s*\\(\\s*var\\s+\\w+\\s*:\\s*counts\\s*\\.\\s*entrySet\\s*\\(\\s*\\)\\s*\\)","message":"Go through the entries with `for (var entry : counts.entrySet())`."}],"forbid":[]}]}