HashMap
A HashMap
is a dictionary collection in Java. It allows us to remember things: strings or ints that have some sort of meaning.
With its fast search algorithm, we would not waste time iterating over keys. We use java.util.HashMap
and call the put()
and get methods.
To use a HashMap
, there are some syntax features we should know about. We must specify types inside angle brackets.
HashMap
with String
keys and Integer values. When we use a diamond, the type arguments are automatically chosen.get()
method. This looks into the HashSet
and, if found, returns the value for the key.System.out.println
to display the values returned by get()
. For "cat" we have 2.import java.util.HashMap; public class Program { public static void main(String[] args) { // Step 1: create new HashMap. HashMap<String, Integer> hash = new HashMap<>(); // Step 2: put 3 keys with values. hash.put("dog", 1); hash.put("cat", 2); hash.put("bird", 3); // Step 3: lookup a known value. int result = hash.get("cat"); // Step 4: display result. System.out.println("RESULT: " + result); } }RESULT: 2
Keys
A HashMap
often contains many keys. We can loop through these keys by first calling the keySet()
method. We loop over the Set returned by keySet
.
HashMap
. This can eliminate the need for a value lookup in the for
-loop.import java.util.HashMap; import java.util.Set; public class Program { public static void main(String[] args) { // Create HashMap of three entries. HashMap<String, Integer> h = new HashMap<>(); h.put("apple", 1); h.put("peach", 2); h.put("guava", 3); // Get keys. Set<String> keys = h.keySet(); // Loop over String keys. for (String key : keys) { System.out.println(key); } } }guava apple peach
entrySet
Each key has a value in the HashMap
. We can loop over these together (without doing additional lookups) by calling entrySet()
in a for
-statement.
HashMap
. We then can call getKey
and getValue
.HashMap
does not remember the order we add items to it. To maintain ordering, please consider a LinkedHashMap
.import java.util.HashMap; import java.util.Map.Entry; public class Program { public static void main(String[] args) { // Create HashMap and put 3 entries in it. HashMap<String, Integer> values = new HashMap<>(); values.put("Java", 6); values.put("Python", 4); values.put("C#", 5); // Loop over HashMap with entrySet. // ... The ordering is not maintained. for (Entry<String, Integer> pair : values.entrySet()) { System.out.println(pair.getKey() + "::" + pair.getValue()); } } }C#::5 Java::6 Python::4
ContainsKey
Sometimes we need no value from the HashMap
. Instead we just want to see if the key exists. We use the containsKey
method for this purpose.
if
-statement.containsKey
method is fast because a hash code is used to locate the key. Using containsValue()
is slower—no hash is available.import java.util.HashMap; public class Program { public static void main(String[] args) { // Create an Integer HashMap. HashMap<Integer, Integer> h = new HashMap<>(); h.put(1, 1000); h.put(20, 1001); h.put(300, 1003); // Use containsKey. if (h.containsKey(1)) { System.out.println("1 was found"); } if (h.containsKey(300)) { System.out.println("300 was found"); } if (!h.containsKey(400)) { System.out.println("400 was not found"); } } }1 was found 300 was found 400 was not found
ContainsValue
returns true if a specified value exists. Keys
are not checked, just values. To get keys with a value, we must use a loop—more than one key may have a single value.
import java.util.HashMap; public class Program { public static void main(String[] args) { // Create a HashMap of fruit and their color. HashMap<String, String> fruit = new HashMap<>(); fruit.put("apple", "red"); fruit.put("orange", "orange"); fruit.put("banana", "yellow"); fruit.put("raspberry", "red"); // See if there is a red value. if (fruit.containsValue("red")) { System.out.println("Red fruit detected!"); // Loop over all keys and print them if they have "red" values. for (String key : fruit.keySet()) { if (fruit.get(key) == "red") { System.out.println(key); } } } } }Red fruit detected! raspberry apple
Size
Every HashMap
has a size. This is the count of entries (or of keys). For each key-value pair we add to HashMap
, its size increases by one. The size()
method returns this count.
import java.util.HashMap; public class Program { public static void main(String[] args) { // ... Create empty HashMap. HashMap<Integer, Integer> map = new HashMap<>(); System.out.println(map.size()); // ... Add one entry. map.put(1, 100); System.out.println(map.size()); // Add two more entries. map.put(2, 200); map.put(3, 300); System.out.println(map.size()); } }0 1 3
IsEmpty
This method returns true if the HashMap
has a size of zero. It is the same as testing "size()
equal to 0," but may be easier to read.
IsEmpty
returns a Boolean
. It is often used within if
-statements, but the Boolean
can be used in any way.import java.util.HashMap; public class Program { public static void main(String[] args) { HashMap<String, Boolean> map = new HashMap<>(); // The HashMap is currently empty. if (map.isEmpty()) { System.out.println("It is empty"); } map.put("cat", true); map.put("dog", false); // IsEmpty now returns false. System.out.println(map.isEmpty()); } }It is empty false
We can get a collection of a HashMap
's values with the values method. We must specify the type for values in the HashMap
. Here we get String
values.
HashMap
. We use a foreach
-loop. Each element is of String
type.import java.util.Collection; import java.util.HashMap; public class Program { public static void main(String[] args) { HashMap<String, String> hash = new HashMap<>(); hash.put("cat", "black"); hash.put("dog", "brown"); hash.put("bird", "blue"); // Get all values from the HashMap. Collection<String> values = hash.values(); for (String value : values) { System.out.println(value); } } }blue black brown
GetOrDefault
With this method, we safely get a value from our HashMap
. If the key does not exist, no error occurs. Instead, the default value (argument 2) is returned.
import java.util.HashMap; public class Program { public static void main(String[] args) { // Create HashMap and put one key. HashMap<Integer, Integer> hash = new HashMap<>(); hash.put(0, 10); // Get keys 0 and 1, returning -1 if nothing there. int result = hash.getOrDefault(0, -1); // Exists int result2 = hash.getOrDefault(1, -1); // Does not exist System.out.println(result); System.out.println(result2); } }10 -1
PutIfAbsent
Put()
will replace an existing value. But putIfAbsent()
will not. It only adds the value to the HashMap
if no key currently exists for it.
putIfAbsent
repeatedly if only the first encountered key needs to be retained.import java.util.HashMap; public class Program { public static void main(String[] args) { // Create HashMap and use putIfAbsent. HashMap<String, Double> hash = new HashMap<>(); hash.putIfAbsent("cat", 1.5); hash.putIfAbsent("cat", 2.0); // ... This returns the first value added. double value = hash.get("cat"); System.out.println(value); } }1.5
Sort
keysA HashMap
is unordered. It cannot be directly sorted, but we can sort its keys and process them (and their values) in order. We use keySet
and add the keys to an ArrayList
.
ArrayList
containing the keys with this method. The keys are now in ascending order.import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Set; public class Program { public static void main(String[] args) { HashMap<String, String> hash = new HashMap<>(); hash.put("red", "color"); hash.put("tomato", "fruit"); hash.put("pizza", "lunch"); // Put keys into an ArrayList and sort it. Set<String> set = hash.keySet(); ArrayList<String> list = new ArrayList<String>(); list.addAll(set); Collections.sort(list); // Display sorted keys and their values. for (String key : list) { System.out.println(key + ": " + hash.get(key)); } } }pizza: lunch red: color tomato: fruit
Sort
EntrySet
, valuesSorting the values in a HashMap
is somewhat complex. We access the EntrySet
, which contains the key-value pairs in the HashMap
.
class
called EntryComparator
. In compare()
it calls compareTo
on the Entry's values.EntrySet
to an ArrayList
which can be sorted. We call addAll
to add the Entries.ArrayList
sort()
, we pass our EntryComparer
. This sorts the ArrayList
of Entries by each Entry's value.import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; import java.util.Map.Entry; class EntryComparator implements Comparator<Entry<String, Integer>> { public int compare(Entry<String, Integer> arg0, Entry<String, Integer> arg1) { // Compare the values. return arg0.getValue().compareTo(arg1.getValue()); } } public class Program { public static void main(String[] args) { // Create HashMap and add four pairs to it. HashMap<String, Integer> hash = new HashMap<>(); hash.put("bird ", 500); hash.put("zebra", 2); hash.put("cat ", 10); hash.put("dog ", 5); // Copy keySet into ArrayList. // ... Sort with EntryComparator. ArrayList<Entry<String, Integer>> copy = new ArrayList<>(); copy.addAll(hash.entrySet()); copy.sort(new EntryComparator()); // Display. for (Entry<String, Integer> e : copy) { System.out.println(e.getKey() + "..." + e.getValue()); } } }zebra...2 dog ...5 cat ...10 bird ...500
Sometimes many methods want to share the same HashMap
. We can place a HashMap
in a class
as a static
field. Then we can access it with static
methods on that class
.
import java.util.HashMap; public class Program { static HashMap<String, String> map = new HashMap<>(); public static void main(String[] args) { // Use static HashMap in static methods. addAnimals(); testAnimals(); } static void addAnimals() { map.putIfAbsent("cat", "black"); map.putIfAbsent("bird", "blue"); } static void testAnimals() { System.out.println(map.getOrDefault("cat", "missing")); System.out.println(map.getOrDefault("?", "missing")); } }black missing
HashMap
In this benchmark we test search speed for the HashMap
and for the ArrayList
. We create 3-element collections, and then try to find elements.
HashMap
for one key. We call containsKey()
on the HashMap
.ArrayList
. We call the contains()
method on the ArrayList
instance.HashMap
delivers a stunning performance boost. It returns the correct result over 2 times faster than the ArrayList
.HashMap
locates an element faster. HashMap
is a clear win.import java.util.HashMap; import java.util.ArrayList; public class Program { public static void main(String[] args) throws Exception { HashMap<Integer, Boolean> hash = new HashMap<>(); hash.put(100, true); hash.put(1000, true); hash.put(50, true); ArrayList<Integer> array = new ArrayList<>(); array.add(100); array.add(1000); array.add(50); long t1 = System.currentTimeMillis(); // Version 1: do HashMap lookups. for (int i = 0; i < 10000000; i++) { if (!hash.containsKey(50)) { throw new Exception(); } } long t2 = System.currentTimeMillis(); // Version 2: do ArrayList lookups. for (int i = 0; i < 10000000; i++) { if (!array.contains(50)) { throw new Exception(); } } long t3 = System.currentTimeMillis(); // ... Times. System.out.println(t2 - t1); System.out.println(t3 - t2); } } 91 ms, HashMap: containsKey 244 ms, ArrayList: contains
HashMap
is an important optimization. Most programs that loop over large arrays can be improved with a HashMap
. But testing is still often needed.