{"id":"list-and-map-internals-own-map","slug":"own-hash-map","title":"A hash map of your own","text":"A list finds a value by its index. A map finds it by its key, and module 32 told how a hash map does that: it keeps its entries in many small groups called **buckets**, and the key's hash code picks the bucket. This step builds one, `SimpleMap<K, V>`, with K for the type of the keys and V for the values, the names HashMap uses too.\n\n### A key and its value\n\nEach entry of the map is a key with its value, an object of a small generic class with two type parameters, like module 44's Duo:\n\n```java\npublic class KeyValue<K, V> {\n    private K key;\n    private V value;\n\n    public KeyValue(K key, V value) {\n        this.key = key;\n        this.value = value;\n    }\n\n    public K getKey() {\n        return this.key;\n    }\n\n    public V getValue() {\n        return this.value;\n    }\n\n    public void setValue(V value) {\n        this.value = value;\n    }\n}\n```\n\nThe value can change, which step 7 needs. The key can't: the bucket a pair sits in depends on its key.\n\n### An array of buckets\n\nEach bucket is a list of pairs, and the map keeps an array of buckets:\n\n```java\nprivate ArrayList<KeyValue<K, V>>[] buckets;\n```\n\nRead the type from the inside out: `KeyValue<K, V>` is one pair, `ArrayList<KeyValue<K, V>>` is a list of pairs, that is one bucket, and the `[]` at the end makes it an array of buckets. (The buckets could be SimpleLists from step 5 just as well; ArrayList keeps the code shorter.)\n\nCreating the array runs into the wall from step 5: `new ArrayList<KeyValue<K, V>>[8]` is a generic array creation, and javac refuses it. Leave out the angle brackets, `new ArrayList[8]`, and it compiles, with the same unchecked note as before. The constructor gets `@SuppressWarnings(\"unchecked\")` again, and puts an empty list in every place of the array:\n\n```java\n@SuppressWarnings(\"unchecked\")\npublic SimpleMap() {\n    this.buckets = new ArrayList[8];\n    for (int i = 0; i < this.buckets.length; i++) {\n        this.buckets[i] = new ArrayList<>();\n    }\n    this.size = 0;\n}\n```\n\n### Picking the bucket\n\nThe key's bucket is the remainder of its hash code divided by the number of buckets, as in module 32's `bucketOf`:\n\n```java\nprivate ArrayList<KeyValue<K, V>> bucketFor(K key) {\n    int index = Math.abs(key.hashCode() % this.buckets.length);\n    return this.buckets[index];\n}\n```\n\n- `key.hashCode()` works for any K, since every object has a `hashCode` (module 32).\n- A hash code can be negative, and then so is the remainder: with 8 buckets it's anything from -7 to 7. `Math.abs` turns that into 0 to 7, always an index the array has. (Java's `Math.floorMod(key.hashCode(), this.buckets.length)` is another way to a remainder that's never negative. It can pick other buckets for negative hash codes, which works just as well, as long as the map always uses the same way.)\n- Equal keys have equal hash codes, so a key always leads to the same bucket. That's how `put` and `get` meet: `get` looks in the bucket where `put` left the pair.\n\n### put and get\n\nHere's the whole map, a first version, as a phone book of the office's extension numbers. To show where each name goes, `main` works out the buckets itself, the same way `bucketFor` does:\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        SimpleMap<String, Integer> extensions = new SimpleMap<>();\n        String[] names = {\"Amara\", \"Bo\", \"Carmen\", \"Dev\", \"Elif\"};\n        int[] numbers = {214, 102, 305, 118, 240};\n        for (int i = 0; i < names.length; i++) {\n            extensions.put(names[i], numbers[i]);\n            System.out.println(names[i] + \" goes to bucket \" + Math.abs(names[i].hashCode() % 8));\n        }\n        System.out.println(\"Dev: \" + extensions.get(\"Dev\"));\n        System.out.println(\"Frank: \" + extensions.get(\"Frank\"));\n        System.out.println(extensions.size() + \" extensions\");\n    }\n}\n// ==== SimpleMap.java ====\nimport java.util.ArrayList;\n\npublic class SimpleMap<K, V> {\n    private ArrayList<KeyValue<K, V>>[] buckets;\n    private int size;\n\n    @SuppressWarnings(\"unchecked\")\n    public SimpleMap() {\n        this.buckets = new ArrayList[8];\n        for (int i = 0; i < this.buckets.length; i++) {\n            this.buckets[i] = new ArrayList<>();\n        }\n        this.size = 0;\n    }\n\n    private ArrayList<KeyValue<K, V>> bucketFor(K key) {\n        int index = Math.abs(key.hashCode() % this.buckets.length);\n        return this.buckets[index];\n    }\n\n    public void put(K key, V value) {\n        bucketFor(key).add(new KeyValue<>(key, value));\n        this.size++;\n    }\n\n    public V get(K key) {\n        for (KeyValue<K, V> pair : bucketFor(key)) {\n            if (pair.getKey().equals(key)) {\n                return pair.getValue();\n            }\n        }\n        return null;\n    }\n\n    public int size() {\n        return this.size;\n    }\n}\n// ==== KeyValue.java ====\npublic class KeyValue<K, V> {\n    private K key;\n    private V value;\n\n    public KeyValue(K key, V value) {\n        this.key = key;\n        this.value = value;\n    }\n\n    public K getKey() {\n        return this.key;\n    }\n\n    public V getValue() {\n        return this.value;\n    }\n\n    public void setValue(V value) {\n        this.value = value;\n    }\n}\n```\n\n```output\nAmara goes to bucket 4\nBo goes to bucket 5\nCarmen goes to bucket 2\nDev goes to bucket 5\nElif goes to bucket 4\nDev: 118\nFrank: null\n5 extensions\n```\n\nAfter the five `put` calls, the buckets look like this:\n\n```text\nbucket 0:  -\nbucket 1:  -\nbucket 2:  Carmen=305\nbucket 3:  -\nbucket 4:  Amara=214, Elif=240\nbucket 5:  Bo=102, Dev=118\nbucket 6:  -\nbucket 7:  -\n```\n\n- `put` adds a new pair to the end of its key's bucket, and counts it.\n- `get(\"Dev\")` works out Dev's bucket, 5, and looks only there: it compares Dev with Bo, then with Dev, and returns 118. The other three names are never looked at.\n- `get(\"Frank\")` goes to bucket 2, finds only Carmen there, and returns `null`, as HashMap's `get` does for a missing key. To find out that Frank isn't there, it looked at one key, not five.\n- The keys are compared with `equals`, never with `==`: a name the user types is a String object of its own (module 32).\n- Five keys in 8 buckets, but only three buckets are used. Hash codes don't spread keys out perfectly, and some keys share a bucket. That's expected, and step 7 looks at it more closely.\n\nThis `put` has a flaw: it never checks whether the key is in the map already. Step 7 fixes that.\n","task":"`SimpleMap.java` is the map from this step, without its `get`. Write `get(K key)`: it returns the value of the key, or `null` when the map doesn't have the key. Look only in the key's own bucket. The check runs:\n\n```java\nSimpleMap<String, Integer> extensions = new SimpleMap<>();\nextensions.put(\"Amara\", 214);\nextensions.put(\"Bo\", 102);\nextensions.put(\"Carmen\", 305);\nSystem.out.println(extensions.get(\"Bo\"));\nSystem.out.println(extensions.get(\"Frank\"));\n```\n\nand expects:\n\n```\n102\nnull\n```\n","kind":"code","seed":"// ==== SimpleMap.java ====\nimport java.util.ArrayList;\n\npublic class SimpleMap<K, V> {\n    private ArrayList<KeyValue<K, V>>[] buckets;\n    private int size;\n\n    @SuppressWarnings(\"unchecked\")\n    public SimpleMap() {\n        this.buckets = new ArrayList[8];\n        for (int i = 0; i < this.buckets.length; i++) {\n            this.buckets[i] = new ArrayList<>();\n        }\n        this.size = 0;\n    }\n\n    private ArrayList<KeyValue<K, V>> bucketFor(K key) {\n        int index = Math.abs(key.hashCode() % this.buckets.length);\n        return this.buckets[index];\n    }\n\n    public void put(K key, V value) {\n        bucketFor(key).add(new KeyValue<>(key, value));\n        this.size++;\n    }\n\n    public V get(K key) {\n        return null;\n    }\n\n    public int size() {\n        return this.size;\n    }\n}\n\n// ==== KeyValue.java ====\npublic class KeyValue<K, V> {\n    private K key;\n    private V value;\n\n    public KeyValue(K key, V value) {\n        this.key = key;\n        this.value = value;\n    }\n\n    public K getKey() {\n        return this.key;\n    }\n\n    public V getValue() {\n        return this.value;\n    }\n\n    public void setValue(V value) {\n        this.value = value;\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        SimpleMap<String, Integer> extensions = new SimpleMap<>();\n        extensions.put(\"Amara\", 214);\n        extensions.put(\"Bo\", 102);\n        extensions.put(\"Carmen\", 305);\n        System.out.println(extensions.get(\"Bo\"));\n        System.out.println(extensions.get(\"Frank\"));\n    }\n}\n","solution":"// ==== SimpleMap.java ====\nimport java.util.ArrayList;\n\npublic class SimpleMap<K, V> {\n    private ArrayList<KeyValue<K, V>>[] buckets;\n    private int size;\n\n    @SuppressWarnings(\"unchecked\")\n    public SimpleMap() {\n        this.buckets = new ArrayList[8];\n        for (int i = 0; i < this.buckets.length; i++) {\n            this.buckets[i] = new ArrayList<>();\n        }\n        this.size = 0;\n    }\n\n    private ArrayList<KeyValue<K, V>> bucketFor(K key) {\n        int index = Math.abs(key.hashCode() % this.buckets.length);\n        return this.buckets[index];\n    }\n\n    public void put(K key, V value) {\n        bucketFor(key).add(new KeyValue<>(key, value));\n        this.size++;\n    }\n\n    public V get(K key) {\n        for (KeyValue<K, V> pair : bucketFor(key)) {\n            if (pair.getKey().equals(key)) {\n                return pair.getValue();\n            }\n        }\n        return null;\n    }\n\n    public int size() {\n        return this.size;\n    }\n}\n\n// ==== KeyValue.java ====\npublic class KeyValue<K, V> {\n    private K key;\n    private V value;\n\n    public KeyValue(K key, V value) {\n        this.key = key;\n        this.value = value;\n    }\n\n    public K getKey() {\n        return this.key;\n    }\n\n    public V getValue() {\n        return this.value;\n    }\n\n    public void setValue(V value) {\n        this.value = value;\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        SimpleMap<String, Integer> extensions = new SimpleMap<>();\n        extensions.put(\"Amara\", 214);\n        extensions.put(\"Bo\", 102);\n        extensions.put(\"Carmen\", 305);\n        System.out.println(extensions.get(\"Bo\"));\n        System.out.println(extensions.get(\"Frank\"));\n    }\n}\n","hints":["`bucketFor(key)` gives the key's bucket, a list of KeyValue pairs. Go through it with `for (KeyValue<K, V> pair : bucketFor(key))`.","Compare with `pair.getKey().equals(key)`, and return `pair.getValue()` when they're equal. After the loop, return `null`."],"tests":[{"name":"Test 1","stdin":"","call":"SimpleMap<String, Integer> extensions = new SimpleMap<>();\nextensions.put(\"Amara\", 214);\nextensions.put(\"Bo\", 102);\nextensions.put(\"Carmen\", 305);\nSystem.out.println(extensions.get(\"Bo\"));\nSystem.out.println(extensions.get(\"Frank\"));\n","expect":"102\nnull","hidden":false},{"name":"Test 2","stdin":"","call":"SimpleMap<String, String> words = new SimpleMap<>();\nwords.put(\"Aa\", \"first\");\nwords.put(\"BB\", \"second\");\nString start = \"B\";\nSystem.out.println(words.get(start + \"B\") + \" \" + words.get(\"Aa\") + \" \" + words.get(\"aa\"));\nSystem.out.println(words.get(\"\") + \" \" + words.size());\n","expect":"second first null\nnull 2","hidden":true},{"name":"Test 3","stdin":"","call":"SimpleMap<Integer, String> lockers = new SimpleMap<>();\nfor (int i = -20; i <= 5000; i += 7) {\n    lockers.put(i, \"L\" + i);\n}\nSystem.out.println(lockers.get(-20) + \" \" + lockers.get(-6) + \" \" + lockers.get(4999) + \" \" + lockers.get(5000));\nSystem.out.println(lockers.get(Integer.valueOf(1000) + 1) + \" \" + lockers.size());\n","expect":"L-20 L-6 L4999 null\nnull 718","hidden":true}],"require":[],"forbid":[{"pattern":"\\bV\\s+get\\s*\\([^)]*\\)\\s*\\{(?:(?!\\bpublic\\b)[\\s\\S])*(?::\\s*(?:this\\s*\\.\\s*)?buckets\\s*\\)|<=?\\s*(?:this\\s*\\.\\s*)?buckets\\s*\\.\\s*length)","message":"`get` doesn't go through every bucket: it looks only in the bucket of its key, `bucketFor(key)`."}],"more":[{"task":"A dry cleaner's map from ticket numbers to customers is the SimpleMap of this step, with 8 buckets. An Integer's hash code is its own value. What does this program print?\n","kind":"predict","seed":"public class Main {\n    public static void main(String[] args) {\n        SimpleMap<Integer, String> tickets = new SimpleMap<>();\n        int[] numbers = {14, 6, 22, -3, 40};\n        String[] names = {\"Rosa\", \"Yusuf\", \"Mila\", \"Tom\", \"Ada\"};\n        for (int i = 0; i < numbers.length; i++) {\n            tickets.put(numbers[i], names[i]);\n        }\n        for (int number : numbers) {\n            System.out.print(Math.abs(Integer.valueOf(number).hashCode() % 8) + \" \");\n        }\n        System.out.println();\n        System.out.println(tickets.get(22) + \" \" + tickets.get(30) + \" \" + tickets.get(-3));\n    }\n}\n// ==== SimpleMap.java ====\nimport java.util.ArrayList;\n\npublic class SimpleMap<K, V> {\n    private ArrayList<KeyValue<K, V>>[] buckets;\n    private int size;\n\n    @SuppressWarnings(\"unchecked\")\n    public SimpleMap() {\n        this.buckets = new ArrayList[8];\n        for (int i = 0; i < this.buckets.length; i++) {\n            this.buckets[i] = new ArrayList<>();\n        }\n        this.size = 0;\n    }\n\n    private ArrayList<KeyValue<K, V>> bucketFor(K key) {\n        int index = Math.abs(key.hashCode() % this.buckets.length);\n        return this.buckets[index];\n    }\n\n    public void put(K key, V value) {\n        bucketFor(key).add(new KeyValue<>(key, value));\n        this.size++;\n    }\n\n    public V get(K key) {\n        for (KeyValue<K, V> pair : bucketFor(key)) {\n            if (pair.getKey().equals(key)) {\n                return pair.getValue();\n            }\n        }\n        return null;\n    }\n}\n// ==== KeyValue.java ====\npublic class KeyValue<K, V> {\n    private K key;\n    private V value;\n\n    public KeyValue(K key, V value) {\n        this.key = key;\n        this.value = value;\n    }\n\n    public K getKey() {\n        return this.key;\n    }\n\n    public V getValue() {\n        return this.value;\n    }\n}\n","solution":"public class Main {\n    public static void main(String[] args) {\n        SimpleMap<Integer, String> tickets = new SimpleMap<>();\n        int[] numbers = {14, 6, 22, -3, 40};\n        String[] names = {\"Rosa\", \"Yusuf\", \"Mila\", \"Tom\", \"Ada\"};\n        for (int i = 0; i < numbers.length; i++) {\n            tickets.put(numbers[i], names[i]);\n        }\n        for (int number : numbers) {\n            System.out.print(Math.abs(Integer.valueOf(number).hashCode() % 8) + \" \");\n        }\n        System.out.println();\n        System.out.println(tickets.get(22) + \" \" + tickets.get(30) + \" \" + tickets.get(-3));\n    }\n}\n// ==== SimpleMap.java ====\nimport java.util.ArrayList;\n\npublic class SimpleMap<K, V> {\n    private ArrayList<KeyValue<K, V>>[] buckets;\n    private int size;\n\n    @SuppressWarnings(\"unchecked\")\n    public SimpleMap() {\n        this.buckets = new ArrayList[8];\n        for (int i = 0; i < this.buckets.length; i++) {\n            this.buckets[i] = new ArrayList<>();\n        }\n        this.size = 0;\n    }\n\n    private ArrayList<KeyValue<K, V>> bucketFor(K key) {\n        int index = Math.abs(key.hashCode() % this.buckets.length);\n        return this.buckets[index];\n    }\n\n    public void put(K key, V value) {\n        bucketFor(key).add(new KeyValue<>(key, value));\n        this.size++;\n    }\n\n    public V get(K key) {\n        for (KeyValue<K, V> pair : bucketFor(key)) {\n            if (pair.getKey().equals(key)) {\n                return pair.getValue();\n            }\n        }\n        return null;\n    }\n}\n// ==== KeyValue.java ====\npublic class KeyValue<K, V> {\n    private K key;\n    private V value;\n\n    public KeyValue(K key, V value) {\n        this.key = key;\n        this.value = value;\n    }\n\n    public K getKey() {\n        return this.key;\n    }\n\n    public V getValue() {\n        return this.value;\n    }\n}\n","hints":["The bucket is the remainder of dividing by 8, without its minus sign: 14 % 8 is 6, and -3 % 8 is -3, which `Math.abs` makes 3.","Three of the tickets share bucket 6. `get(22)` looks in bucket 6 and finds 22 there. `get(30)` looks in bucket 6 too, but none of its keys equals 30."],"tests":[{"name":"Output","stdin":"","expect":"6 6 6 3 0\nMila null Tom","hidden":false}],"require":[],"forbid":[],"lines":["6 6 6 3 0","Mila null Tom"]},{"task":"Two more methods for `SimpleMap.java`, like HashMap's:\n\n- `containsKey(K key)`, which returns `true` if the map has the key. A key's value may be `null`, so look for the key itself, not its value.\n- `keys()`, which returns a new `ArrayList<K>` with all the keys, bucket by bucket: first the keys in bucket 0, in the order they were put there, then the keys in bucket 1, and so on.\n\nThat's also why Java's HashMap lists its keys in an order that looks random: it goes through its buckets too. The check runs:\n\n```java\nSimpleMap<String, Integer> extensions = new SimpleMap<>();\nString[] names = {\"Amara\", \"Bo\", \"Carmen\", \"Dev\", \"Elif\"};\nfor (int i = 0; i < names.length; i++) {\n    extensions.put(names[i], 100 + i);\n}\nSystem.out.println(extensions.keys());\nSystem.out.println(extensions.containsKey(\"Elif\") + \" \" + extensions.containsKey(\"Frank\"));\n```\n\nand expects:\n\n```\n[Carmen, Amara, Elif, Bo, Dev]\ntrue false\n```\n","kind":"code","seed":"// ==== SimpleMap.java ====\nimport java.util.ArrayList;\n\npublic class SimpleMap<K, V> {\n    private ArrayList<KeyValue<K, V>>[] buckets;\n    private int size;\n\n    @SuppressWarnings(\"unchecked\")\n    public SimpleMap() {\n        this.buckets = new ArrayList[8];\n        for (int i = 0; i < this.buckets.length; i++) {\n            this.buckets[i] = new ArrayList<>();\n        }\n        this.size = 0;\n    }\n\n    private ArrayList<KeyValue<K, V>> bucketFor(K key) {\n        int index = Math.abs(key.hashCode() % this.buckets.length);\n        return this.buckets[index];\n    }\n\n    public void put(K key, V value) {\n        bucketFor(key).add(new KeyValue<>(key, value));\n        this.size++;\n    }\n\n    public V get(K key) {\n        for (KeyValue<K, V> pair : bucketFor(key)) {\n            if (pair.getKey().equals(key)) {\n                return pair.getValue();\n            }\n        }\n        return null;\n    }\n\n    public int size() {\n        return this.size;\n    }\n\n    // Write containsKey and keys here.\n}\n\n// ==== KeyValue.java ====\npublic class KeyValue<K, V> {\n    private K key;\n    private V value;\n\n    public KeyValue(K key, V value) {\n        this.key = key;\n        this.value = value;\n    }\n\n    public K getKey() {\n        return this.key;\n    }\n\n    public V getValue() {\n        return this.value;\n    }\n\n    public void setValue(V value) {\n        this.value = value;\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        SimpleMap<String, Integer> extensions = new SimpleMap<>();\n        String[] names = {\"Amara\", \"Bo\", \"Carmen\", \"Dev\", \"Elif\"};\n        for (int i = 0; i < names.length; i++) {\n            extensions.put(names[i], 100 + i);\n        }\n        System.out.println(extensions.keys());\n        System.out.println(extensions.containsKey(\"Elif\") + \" \" + extensions.containsKey(\"Frank\"));\n    }\n}\n","solution":"// ==== SimpleMap.java ====\nimport java.util.ArrayList;\n\npublic class SimpleMap<K, V> {\n    private ArrayList<KeyValue<K, V>>[] buckets;\n    private int size;\n\n    @SuppressWarnings(\"unchecked\")\n    public SimpleMap() {\n        this.buckets = new ArrayList[8];\n        for (int i = 0; i < this.buckets.length; i++) {\n            this.buckets[i] = new ArrayList<>();\n        }\n        this.size = 0;\n    }\n\n    private ArrayList<KeyValue<K, V>> bucketFor(K key) {\n        int index = Math.abs(key.hashCode() % this.buckets.length);\n        return this.buckets[index];\n    }\n\n    public void put(K key, V value) {\n        bucketFor(key).add(new KeyValue<>(key, value));\n        this.size++;\n    }\n\n    public V get(K key) {\n        for (KeyValue<K, V> pair : bucketFor(key)) {\n            if (pair.getKey().equals(key)) {\n                return pair.getValue();\n            }\n        }\n        return null;\n    }\n\n    public int size() {\n        return this.size;\n    }\n\n    public boolean containsKey(K key) {\n        for (KeyValue<K, V> pair : bucketFor(key)) {\n            if (pair.getKey().equals(key)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    public ArrayList<K> keys() {\n        ArrayList<K> keys = new ArrayList<>();\n        for (ArrayList<KeyValue<K, V>> bucket : this.buckets) {\n            for (KeyValue<K, V> pair : bucket) {\n                keys.add(pair.getKey());\n            }\n        }\n        return keys;\n    }\n}\n\n// ==== KeyValue.java ====\npublic class KeyValue<K, V> {\n    private K key;\n    private V value;\n\n    public KeyValue(K key, V value) {\n        this.key = key;\n        this.value = value;\n    }\n\n    public K getKey() {\n        return this.key;\n    }\n\n    public V getValue() {\n        return this.value;\n    }\n\n    public void setValue(V value) {\n        this.value = value;\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        SimpleMap<String, Integer> extensions = new SimpleMap<>();\n        String[] names = {\"Amara\", \"Bo\", \"Carmen\", \"Dev\", \"Elif\"};\n        for (int i = 0; i < names.length; i++) {\n            extensions.put(names[i], 100 + i);\n        }\n        System.out.println(extensions.keys());\n        System.out.println(extensions.containsKey(\"Elif\") + \" \" + extensions.containsKey(\"Frank\"));\n    }\n}\n","hints":["`containsKey` looks in the key's own bucket, like `get`, and returns `true` when a pair's key equals the key. Why not `return get(key) != null;`? It would say `false` for a key whose value is `null`.","`keys()` needs two loops: one over the buckets, `for (ArrayList<KeyValue<K, V>> bucket : this.buckets)`, and inside it one over the pairs of that bucket, adding each `pair.getKey()` to a new `ArrayList<K>`."],"tests":[{"name":"Test 1","stdin":"","call":"SimpleMap<String, Integer> extensions = new SimpleMap<>();\nString[] names = {\"Amara\", \"Bo\", \"Carmen\", \"Dev\", \"Elif\"};\nfor (int i = 0; i < names.length; i++) {\n    extensions.put(names[i], 100 + i);\n}\nSystem.out.println(extensions.keys());\nSystem.out.println(extensions.containsKey(\"Elif\") + \" \" + extensions.containsKey(\"Frank\"));\n","expect":"[Carmen, Amara, Elif, Bo, Dev]\ntrue false","hidden":false},{"name":"Test 2","stdin":"","call":"SimpleMap<Integer, String> map = new SimpleMap<>();\nSystem.out.println(map.keys() + \" \" + map.containsKey(3));\nint[] keys = {17, 3, -9, 8, 11, 0, 24};\nfor (int key : keys) {\n    map.put(key, null);\n}\nSystem.out.println(map.keys());\nSystem.out.println(map.containsKey(11) + \" \" + map.containsKey(19) + \" \" + map.containsKey(-9) + \" \" + map.containsKey(9));\n","expect":"[] false\n[8, 0, 24, 17, -9, 3, 11]\ntrue false true false","hidden":true},{"name":"Test 3","stdin":"","call":"SimpleMap<String, String> map = new SimpleMap<>();\nmap.put(\"Aa\", \"x\");\nmap.put(\"BB\", \"y\");\nmap.put(\"Oakdale\", \"z\");\nString typed = \"Oak\";\nSystem.out.println(map.keys() + \" \" + map.containsKey(typed + \"dale\") + \" \" + map.containsKey(\"AaBB\"));\n","expect":"[Aa, BB, Oakdale] true false","hidden":true}],"require":[],"forbid":[]}]}