In this article, we will explain what a HashMap
is, analyze the constructors and methods of HashMap class in Java, and then go through a real-world use case of HashMap.
1. What is a HashMap and how it works
HashMap in Java is a Key-Value Data Structure. The HashMap
class in Java inherits from AbstractMap
class and implements the Map interface.
1.1 Visualization of HashMap
To visualize a HashMap
below is a diagram:
This is an example of a HashMap with an Integer
as the key type, and a String
as the value type. The data is stored as key-value pairs and each key maps to only one value. An entry is a key-value pair.
1.2 HashMap Java Data Structure characteristics
HashMap
in Java has the following characteristics:
- Key can have
null
value but for example, if we runmap.put(null, 5)
and thenmap.put(null, 6)
, the value will be6
. Sonull
is a unique key and only one can exist in the HashMap. - Value can be
null
- Insertion order can not be guaranteed
- Time complexity of
get()
,put()
,remove()
,containsKey()
- On Average: O(1)
- Worst case: O(n)
2. HashMap Constructors – How to initialize a HashMap in Java
HashMap class in Java has 4 constructors and before we dig into explaining them, there are 3 important attributes to be explained. Note that in order to import the HashMap class from java.util package, you have to add this line: import java.util.HashMap;
Capacity: The number of elements currently allowed to exist in the HashMap. The default value is 16 and the maximum is 230.
Load Factor: The upper limit (in percentage) after which the HashMap will be resized. The default value is 0.75 ( 75%)
Threshold: This is the product of the Load factor and the Capacity, if this threshold is surpassed, the HashMap will be resized.
Considering the above, using the default values, the HashMap will resize after 16*0.75 = 12 elements are inserted in the map.
Let’s explain each one of the constructors.
2.1 HashMap() constructor
This is the simplest and most used way to initialize a HashMap. It takes nothing as a parameter and uses the default capacity and load factor.
public static void noParametersConstructor(){ /* Initialize a hashmap with the no-parameters constructor * Note that the type parameters cannot be primitive types */ HashMap<Integer, String> namesMap = new HashMap<>(); namesMap.put(1,"Giorgos"); namesMap.put(2,"Dimitris"); namesMap.put(3,"Giannis"); namesMap.put(4,"Nikolaos"); namesMap.put(5,"Akis"); // Print all the entries in the map System.out.println("Printing all the entries - no argument constructor"); namesMap.entrySet().forEach(System.out::println); System.out.println(); }
The output is the above:
Printing all the entries - no argument constructor 1=Giorgos 2=Dimitris 3=Giannis 4=Nikolaos 5=Akis
2.2 HashMap(int initialCapacity) constructor
This constructor accepts the initial capacity to be used as a parameter. You might want to use this constructor for better performance when the number of elements that the map will contain is known.
public static void initialCapacityConstructor() { /* Initialize a hashmap with the constructor taking the initialCapacity * Hadn't we set the initial capacity, the constructor would resize after the 12th element ( 0.75 load factor * 16 initial capacity = 12 ) */ HashMap<Integer, String> numbersMap = new HashMap<>(100); // Now it will resize after the 75th element has been instered ( 0.75 load factor * 100 initial capacity = 75 ) for (int i = 0; i < 100; i++) numbersMap.put(i, "A" + i); }
2.3 HashMap(int initialCapacity, float loadFactor) constructor
This constructor accepts both the initial capacity and the load factor. This constructor could alter the threshold after which the map will resize.
public static void initialCapacityAndLoadFactorConstructor() { /* Initialize a hashmap with the constructor taking the initialCapacity and the loadFactor * Hadn't we set the initial capacity, the constructor would resize after the 12th element (0.75 load factor * 16 initial capacity = 12 ) * Now it will resize after the 90th element has been inserted (0.9 load factor * 100 initial capacity) */ HashMap<Integer, String> numbersMap = new HashMap<Integer, String>(100,0.9f); for (int i = 0; i < 100; i++) numbersMap.put(i, "A" + i); }
2.4 HashMap(Map<? extends K, ? extends V> m) constructor
This constructor accepts another map and puts the elements in the new map that is constructed.
The load factor used is the default (0.75), and the initial capacity is enough to hold the data.
public static void otherMapConstructorConstructor() { // Here is the map we used in the first example HashMap<Integer, String> namesMap = new HashMap<>(); namesMap.put(1,"Giorgos"); namesMap.put(2,"Dimitris"); namesMap.put(3,"Giannis"); namesMap.put(4,"Nikolaos"); namesMap.put(5,"Akis"); // Now we create a new HashMap by using the namesMap HashMap HashMap<Integer, String> newNamesMap = new HashMap<>(namesMap); // We fill it with more entries newNamesMap.put(6, "Petros"); newNamesMap.put(7, "Panagiotis"); //Print the result System.out.println("Printing all the entries - using the constructor accepting other map"); newNamesMap.entrySet().forEach(System.out::println); }
Printing all the entries - using the constructor accepting other map 1=Giorgos 2=Dimitris 3=Giannis 4=Nikolaos 5=Akis 6=Petros 7=Panagiotis
Now that you know how to initialize a HashMap based on your needs, let’s move on with HashMap methods.
2.5 Initialize a HashMap in Java 19 Using the newHashMap(int numMappings) Static Method
In Java 19, a new way to create a HashMap was introduced so you will be able to create a new HashMap by providing a number of expected mappings.
By using this method, you won’t have to do any calculations like before, for instance:
With new HashMap(int initialCapacity)
, If we wanted our map to resize at 1000 elements, we should calculate that with a default load factor 75%, the initial capacity should be 1333 to make the map resize after the 1000th element.
On the other hand, with newHashMap(int numMappings)
, we do not need to do such calculations and we can just write:
// Java 19 and After HashMap<String, String> map = HashMap.newHashMap(1000); //This is the before Java 19 equivalent HashMap<String, String> map = new HashMap<>(1333);
3. HashMap Methods
In this section, we will go one by one method provided by the HashMap class and explain how it works with detailed examples
3.1 Putting entries into a HashMap
3.1.1 V put( K key, V value)
- Parameters: the key and the value of the mapping to be inserted.
- Returns the value after insertion.
Note that if the key already exists, the value will be replaced.
public static void put(){ HashMap<Integer, String> namesMap = new HashMap<>(); /* put( K key, V value) inserts entries in the map * by providing the key and the value, the ordering is * preserved * It returns the value of the mapping */ namesMap.put(1, "Sofoklis"); namesMap.put(2, "Platonas"); namesMap.put(3, "Aristotelis"); //print the result System.out.println("HashMap after calling 3 times the put() method : "); namesMap.entrySet().forEach(System.out::println); System.out.println(); // If key already exists, it will be replaced namesMap.put(2,"Periklis"); System.out.println("HashMap after calling put method with key 2 -> Periklis : "); namesMap.entrySet().forEach(System.out::println); System.out.println(); }
Output:
HashMap after calling 3 times the put() method : 1=Sofoklis 2=Platonas 3=Aristotelis HashMap after calling put method with key 2 -> Platonas : 1=Sofoklis 2=Periklis 3=Aristotelis
3.1.2 V putIfAbsent(K key, V value)
- Parameters: the key and the value to be inserted.
- Returns the value after insertion.
Note that unlike put()
, this method will not replace the value if the key exists.
public static void putIfAbsent(){ /* putIfAbsent(K key, V value) * inserts the mapping only if the key is not taken * It returns the value */ HashMap<Integer, String> namesMap = new HashMap<>(); /* putIfAbsent(K key, V value) inserts entries in the map * by providing the key and the value, the ordering is * preserved * It returns the value of the mapping */ namesMap.put(1, "Sofoklis"); namesMap.put(2, "Platonas"); namesMap.put(3, "Aristotelis"); //print the result System.out.println("HashMap after calling 3 times the put() method : "); namesMap.entrySet().forEach(System.out::println); System.out.println(); // This will not replace the mapping, it already exists namesMap.putIfAbsent(2,"Periklis"); // This will work like put() namesMap.putIfAbsent(4,"Leonidas"); System.out.println("HashMap after calling putIfAbsent() method with key 2 -> Platonas and with key 4 -> Leonidas: "); namesMap.entrySet().forEach(System.out::println); System.out.println(); }
Output:
HashMap after calling 3 times the put() method : 1=Sofoklis 2=Platonas 3=Aristotelis HashMap after calling putIfAbsent() method with key 2 -> Platonas and with key 4 -> Leonidas: 1=Sofoklis 2=Platonas 3=Aristotelis 4=Leonidas
3.1.3 void putAll(Map<? extends K, ? extends V> m)
- Parameters: The Map whose entries are to be added to this Hashmap.
Copies all the entries of a map into the hashmap calling this method.
In addition, it works like put()
, which means that if any entry on the map to be copied has the same key as in the Hashmap calling the method, the value will be replaced.
public static void putAll(){ /* putAll(Map<? extends K,? extends V> m) * copies all the entries from one map into another */ HashMap<Integer, String> namesMap = new HashMap<>(); /* put( K key, V value) inserts entries in the map * by providing the key and the value, the ordering is * preserved */ namesMap.put(1, "Sofoklis"); namesMap.put(2, "Platonas"); namesMap.put(3, "Aristotelis"); HashMap<Integer, String> namesMapFemales = new HashMap<>(); //Be careful - if the key already exists, it will be replaced, e.g. entry 3 namesMapFemales.put(4, "Evi"); namesMapFemales.put(5, "Filio"); namesMapFemales.put(3, "Anna"); namesMap.putAll(namesMapFemales); //print the result System.out.println("HashMap after calling putAll() method : "); namesMap.entrySet().forEach(System.out::println); System.out.println(); }
Output:
HashMap after calling putAll() method : 1=Sofoklis 2=Platonas 3=Anna 4=Evi 5=Filio
3.2 Accesing a HashMap
3.2.1 V get(Object Key)
- Parameter: The key in order to access the value of the entry.
- Returns the value if a mapping exists, otherwise, it returns
null
.
public static void get(){ /* get(Object key) * returns tha value given a specific key */ HashMap<Integer, String> namesMap = new HashMap<>(); namesMap.put(1, "Sofoklis"); namesMap.put(2, "Platonas"); namesMap.put(3, "Aristotelis"); // This will print Sofoklis as there is a mapping for key 1 System.out.println(namesMap.get(1)); // This will print null as there isn't a mapping for key 5 System.out.println(namesMap.get(5)); }
Output:
Sofoklis null
3.2.2 V getOrDefault(Object key, V defaultValue)
- Parameters: The key to access the entry and the default value if the key does not exist.
- Returns: Either the value mapped to the key, or the default value if there isn’t any mapping.
public static void getOrDefault(){ /* getOrDefault(Object key, V defaultValue) * returns the value given a specific key, and if this key does not exist, returns the defaultValue */ HashMap<Integer, String> namesMap = new HashMap<>(); namesMap.put(1, "Sofoklis"); namesMap.put(2, "Platonas"); namesMap.put(3, "Aristotelis"); // This will print Sofoklis as there is a mapping for key 2 System.out.println(namesMap.getOrDefault(2,"God")); // This will print God as there isn't a mapping for key 10 System.out.println(namesMap.getOrDefault(10,"God")); }
Output:
Platonas God
3.2.3 Set<K> keySet()
- Accepts no parameters.
- Returns a Set containing all the keys in this Hashmap.
public static void keySet(){ /* keySet() * returns all the keys that exist in this hashmap */ HashMap<Integer, String> namesMap = new HashMap<>(); namesMap.put(1, "Sofoklis"); namesMap.put(2, "Platonas"); namesMap.put(3, "Aristotelis"); // This will return all the keys that exist in the hashmap System.out.println("Keys in the hashmap:"); namesMap.keySet().forEach(System.out::println); System.out.println(); // This will filter all the keys > 1 System.out.println("Mappings of keys with value > 1 in this map : "); namesMap.keySet().stream() .filter(k -> k > 1) .map(namesMap::get) .collect(Collectors.toSet()) .forEach(System.out::println); System.out.println(); }
Output:
Keys in the hashmap: 1 2 3 Mappings of keys with value > 1 in this map : Aristotelis Platonas
3.2.4 Collection<V> values()
- Accepts no parameters.
- Returns a
Collection
containing all the values of the Map.
public static void values(){ /* values() * returns all the values as a collection */ HashMap<Integer, String> namesMap = new HashMap<>(); namesMap.put(1, "Sofoklis"); namesMap.put(2, "Platonas"); namesMap.put(3, "Aristotelis"); namesMap.put(4, "Georgios"); // Getting all the values as a Collection Collection<String> values = namesMap.values(); //print all the values System.out.println("Values: "); values.forEach(System.out::println); System.out.println(); // Note that if we put/remove an entry, the values collection will also be updated namesMap.remove(4); // values collection after removal of key 4 System.out.println("Values after removal of key 4: "); values.forEach(System.out::println); }
Output:
Values: Sofoklis Platonas Aristotelis Georgios Values after removal of key 4: Sofoklis Platonas Aristotelis
3.2.5 Set<Map.Entry<K, V>> entrySet()
- Accepts no parameters.
- Returns a
Set
containing all the entries of this Hashmap.
The example below will answer questions like “How to iterate hashmap in java?” and explain how entrySet()
method works.
public static void entrySet(){ /* entrySet() * returns all the entries of the hashmap */ HashMap<Integer, String> namesMap = new HashMap<>(); namesMap.put(1, "Sofoklis"); namesMap.put(2, "Platonas"); namesMap.put(3, "Aristotelis"); // Traversing the entries before java 8 for (Map.Entry entry : namesMap.entrySet()){ //actions } System.out.println(); // Traversing the entries - Java 8 System.out.println("Entries in the hashmap:"); namesMap.entrySet().forEach(System.out::println); System.out.println(); // This will filter all the entries whose value starts with A and then return the key of these entries // and then print them System.out.println("Keys with value starting with A in this map : "); namesMap.entrySet().stream() .filter(x -> x.getValue().startsWith("A")) .map(Map.Entry::getKey) .collect(Collectors.toSet()) .forEach(System.out::println); System.out.println(); }
Output:
Entries in the hashmap: 1=Sofoklis 2=Platonas 3=Aristotelis Keys with value starting with A in this map : 3
3.3 Modifying entries of a Hashmap
All HashMap methods that have the ability to modify entries of the Map use Java 8 functions and lambdas. The only methods that do not require a lambda are replace()
methods.
3.3.1 V replace( K key, V value)
- Parameters: The key and the value to be replaced.
- Returns: The new value that was replaced if the key exists, else, returns
null
.
It can be used to replace a value only if the key provided exists.
public static void replace(){ /* replace( K key, V value) * This method replaces the value provided a specific * key is given, and then returns the new value */ HashMap<Integer, String> carsBrandsMap = new HashMap<>(); carsBrandsMap.put(1, "BMW"); carsBrandsMap.put(2, "Toyota"); carsBrandsMap.put(3, "Opel"); // Let's replace Toyota with Lexus carsBrandsMap.replace(2, "Lexus"); //print the result System.out.println("Printing after replace:"); carsBrandsMap.entrySet().forEach(System.out::println); System.out.println(); // Let's try to replace a key that isn't in the hashmap // this will return null String mercedes = carsBrandsMap.replace(5,"Mercedes"); System.out.println(mercedes); }
Output:
Printing after replace: 1=BMW 2=Lexus 3=Opel null
3.3.2 boolean replace(K key, V oldValue, V newValue)
- Parameters: The specific key, the old value that the mapping must have, the new value which will replace the old.
- Returns: true is replacement worked, false if it didn’t.
public static void replaceWithOldValue(){ /* replace( K key, V oldValue, V newValue) * This method replaces the value provided a specific * key is given, but only if the mapping */ HashMap<Integer, String> carsBrandsMap = new HashMap<>(); carsBrandsMap.put(1, "BMW"); carsBrandsMap.put(2, "Toyota"); carsBrandsMap.put(3, "Opel"); System.out.println(); System.out.println("Initial HashMap: "); carsBrandsMap.entrySet().forEach(System.out::println); System.out.println(); // Let's replace Toyota with Lexus System.out.println("Replacing Toyota with Lexus:"); System.out.println(); boolean done = carsBrandsMap.replace(2, "Toyota","Lexus"); System.out.println("Was it successful? "+done); System.out.println(); carsBrandsMap.entrySet().forEach(System.out::println); System.out.println(); //What if we want to replace Opel, but we make a mistake done = carsBrandsMap.replace(3,"Opal","Lamborghini"); System.out.println("Was it successful? "+done); System.out.println(); //print the result System.out.println("After trying to replace Opel with a typo, with Lamborghini:"); carsBrandsMap.entrySet().forEach(System.out::println); System.out.println(); }
Output:
Initial HashMap: 1=BMW 2=Toyota 3=Opel Replacing Toyota with Lexus: Was it successful? true 1=BMW 2=Lexus 3=Opel Was it successful? false After trying to replace Opel with Lamborghini with typo: 1=BMW 2=Lexus 3=Opel
3.3.3 void replaceAll(BiFunction<? super K, ? super V, ? extends V> function)
HashMap method replaceAll was added in Java 8 to allow us to replace multiple entries without having to call the 2 previous replace methods multiple times.
- Parameter: A function which accepts the key and the value of each entry and returns the new value.
- Returns nothing
public static void replaceAll(){ /* replaceAll(BiFunction<? super K, ? super V, ? extends V> function) * This method replaces all the mappings based on the Bifunction * provided as a Parameter * */ HashMap<Integer, String> carsBrandsMap = new HashMap<>(); carsBrandsMap.put(1, "BMW"); carsBrandsMap.put(2, "Toyota"); carsBrandsMap.put(3, "Opel"); System.out.println(); System.out.println("Initial HashMap: "); carsBrandsMap.entrySet().forEach(System.out::println); System.out.println(); // Let's say we want to replace the brands with the brand provided + a specific model // It accepts the key and the value of the specific entry as parameters and returns the new value carsBrandsMap.replaceAll( (key, value) -> { switch (value){ case "BMW" : return value.concat(" M3 GTR"); case "Toyota" : return value.concat(" Supra"); case "Opel" : return value.concat(" Astra"); default : return value; } }); // print the result carsBrandsMap.entrySet().forEach(System.out::println); }
Output:
Initial HashMap: 1=BMW 2=Toyota 3=Opel HashMap after replaceAll: 1=BMW M3 GTR 2=Toyota Supra 3=Opel Astra
3.3.4 V compute(K key, BiFunction<? super K, ? super V, ? extends V> function)
HashMap method compute was also added in Java 8 and allows us to combine different entries with a specific key and change the value of the mapping of the key.
- Parameters: The key whose value will be affected and a fuction which accepts the key and the value of the mapping, and returns the new value.
- Returns the new value after insertion.
The problem with this method is that if the key maps to a null
value or the key doesn’t exist, a NullPointerException
will be produced.
Below is a demonstration of compute()
:
public static void compute(){ /* compute(K key, BiFunction<? super K, ? super V, ? extends V> function) * This method can change the value, provided a key and * by using a function which accepts the key and the value * and returns the new value */ HashMap<Integer, String> carsBrandsMap = new HashMap<>(); carsBrandsMap.put(1, "BMW"); carsBrandsMap.put(2, "Toyota"); carsBrandsMap.put(3, "Opel"); System.out.println(); System.out.println("Initial HashMap: "); carsBrandsMap.entrySet().forEach(System.out::println); System.out.println(); // Let's say we want to replace only Toyota with the Brand Name + the model name // The compute method accepts the key and a function which will use the this specific key carsBrandsMap.compute(2, (key ,value) -> value.concat(" Corolla")); // print the result System.out.println("HashMap after compute:"); carsBrandsMap.entrySet().forEach(System.out::println); //Everything worked fine, only the entry with key 2 was affected, but what if the value was null? carsBrandsMap.put(4,null); try { System.out.println(); System.out.println("Trying to compute with null value..."); //this will produce NullPointerException carsBrandsMap.compute(4, (key ,value) -> value.concat(" Gallardo")); System.out.println(); } catch (NullPointerException exception){ System.out.println("You should have used another method or check if null"); System.out.println(); try { // try to compute for a key that does not exist, will also produce NPE System.out.println("Trying to compute with a key that does not exist..."); carsBrandsMap.compute(8, (key ,value) -> value.concat(" Gallardo")); } catch (NullPointerException e){ System.out.println("You should have used another method or check if null"); System.out.println(); } } }
Output:
Initial HashMap: 1=BMW 2=Toyota 3=Opel HashMap after compute: 1=BMW 2=Toyota Corolla 3=Opel Trying to compute with null value... You should have used another method or check if null Trying to compute with a key that does not exist... You should have used another method or check if null
3.3.5 V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> function)
- Parameters: The key whose value will be affected and a function which accepts the key and the value of the mapping, and returns the new value.
- Returns the new value after insertion.
The difference with compute()
is that if the key is null
or it doesn’t exist, it will not produce NullPointerException
, it will just ignore this key and go on.
public static void computeIfPresent(){ // To avoid the null pointer exception when using compute() you can use /* computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> function) * This method can change the value, provided a key and * by using a function which accepts the key and the value * and returns the new value. * This will happen only if the key exists and it is not null */ HashMap<Integer, String> carsBrandsMap = new HashMap<>(); carsBrandsMap.put(1, "BMW"); carsBrandsMap.put(2, "Toyota"); carsBrandsMap.put(3, "Opel"); carsBrandsMap.put(4, null); System.out.println(); System.out.println("Initial HashMap: "); carsBrandsMap.entrySet().forEach(System.out::println); System.out.println(); // This will not produce NPE and it will do nothing carsBrandsMap.computeIfPresent(4, (key ,value) -> value.concat(" Gallardo")); // This will also do nothing as key 8 does not exist carsBrandsMap.computeIfPresent(8, (key ,value) -> value.concat(" Gallardo")); System.out.println("Printing the entries after computeIfPresent:"); carsBrandsMap.entrySet().forEach(System.out::println); System.out.println(); // adding a dot after each value //This will not produce NPE as the null value will be ignored carsBrandsMap.keySet() .forEach(key -> carsBrandsMap.computeIfPresent(key, (k, v) -> v.concat("."))); // printing after adding a dot to each entry System.out.println("HashMap after adding a dot to the end for each value"); carsBrandsMap.entrySet().forEach(System.out::println); }
Output:
Initial HashMap: 1=BMW 2=Toyota 3=Opel 4=null Printing the entries after computeIfPresent: 1=BMW 2=Toyota 3=Opel 4=null HashMap after adding a dot to the end for each value 1=BMW. 2=Toyota. 3=Opel. 4=null
3.3.6 V computeIfAbsent(K key, Function<? super K, ? extends V> function)
- Parameters: The key whose value will be affected and a function which accepts the key and returns the new value.
- Returns the new value after insertion.
The difference with compute()
is that it will only act if any of the following is true:
- The key doesn’t exist.
- The value of the key specified is
null
.
Below is a demonstration:
public static void computeIfAbsent(){ /* computeIfAbsent(K key, Function<? super K, ? extends V> function) * This method can change the value, provided a specific key and * by using a function which accepts the key * and returns the new value. * This will happen only if the key is null or it doesn't exist. */ HashMap<Integer, String> carsBrandsMap = new HashMap<>(); carsBrandsMap.put(1, "BMW"); carsBrandsMap.put(2, "Toyota"); carsBrandsMap.put(3, "Opel"); carsBrandsMap.put(4, null); carsBrandsMap.put(5, null); carsBrandsMap.put(7, null); System.out.println(); System.out.println("Initial HashMap: "); carsBrandsMap.entrySet().forEach(System.out::println); System.out.println(); // This will add a new entry 6 -> Ferrari carsBrandsMap.computeIfAbsent(6, key -> carsBrandsMap.put(key,"Ferrari")); // This will do nothing, as there is already an entry with key 6 carsBrandsMap.computeIfAbsent(6, key -> carsBrandsMap.put(key,"VW")); // This will put the value Honda, for every key that maps to a null value carsBrandsMap.keySet() .forEach(key -> carsBrandsMap.computeIfAbsent(key, k -> carsBrandsMap.put(k, "Honda") )); System.out.println("Map after computeIfAbsent"); carsBrandsMap.entrySet().forEach(System.out::println); }
Output:
Initial HashMap: 1=BMW 2=Toyota 3=Opel 4=null 5=null 7=null Map after computeIfAbsent 1=BMW 2=Toyota 3=Opel 4=Honda 5=Honda 6=Ferrari 7=Honda
3.3.7 V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> function)
This HashMap method was also added in Java 8, and it allows us to combine an old value with a value and produce a new value for a specific key. Of course, the BiFunction
passed as a parameter will produce this new value.
Parameters:
- The key whose value will be affected.
- The value to be associated with the old value.
- A function that accepts the old value and a value to be associated with the old value, and returns the new value.
Returns: The new value.
public static void merge(){ /* merge(K key,V value, BiFunction<? super V, ? super V, ? extends V> function) * The merge method accepts the key, the value to be associated with the old value and * a function which accepts the old Value, * the value given as the 2nd parameter in the merge method * and returns the result */ HashMap<Integer, String> carsBrandsMap = new HashMap<>(); carsBrandsMap.put(1, "BMW"); carsBrandsMap.put(2, "Toyota"); carsBrandsMap.put(3, "Opel"); System.out.println(); System.out.println("Initial HashMap: "); carsBrandsMap.entrySet().forEach(System.out::println); System.out.println(); // Let's say we want to add the model only for Toyota //This carsBrandsMap.merge(2," Corolla",String::concat); // is the same as this //carsBrandsMap.merge(2," Corolla",(val,newVal) -> val.concat(newVal)); // print the result System.out.println("HashMap after merging:"); carsBrandsMap.entrySet().forEach(System.out::println); }
Output:
Initial HashMap: 1=BMW 2=Toyota 3=Opel HashMap after merging: 1=BMW 2=Toyota Corolla 3=Opel
3.4 Removing entries from a HashMap
3.4.1 V remove( K key)
- Parameter: The specific key in order to remove an entry
- Returns: The value of the entry removed if the entry exists, or
null
if the key was absent
public static void remove(){ /* remove(K key) * This method removes an entry based on the key provided. * It returns the value of the mapping tha was removed */ HashMap<String, String> countriesCapitalsMap = new HashMap<>(); countriesCapitalsMap.put("Greece", "Athens"); countriesCapitalsMap.put("Spain", "Madrid"); countriesCapitalsMap.put("Italy", "Rome"); System.out.println("Initial Map:"); countriesCapitalsMap.entrySet().forEach(System.out::println); System.out.println(); //Will return Athens countriesCapitalsMap.remove("Greece"); System.out.println("Map after removal of Greece:"); countriesCapitalsMap.entrySet().forEach(System.out::println); System.out.println(); }
Output:
Initial Map: Greece=Athens Italy=Rome Spain=Madrid Map after removal of Greece: Italy=Rome Spain=Madrid
3.4.2 boolean remove(K key, V value)
- Parameter: The specific key in order to remove an entry and the value the mapping must have, so as the removal succeeds
- Returns: true if the removal succeeded, false if it did not.
public static void removeWithValue(){ /* remove(K key, V Value) * This method removes an entry based on the key provided, * only if the key is mapped to the given value */ HashMap<String, String> countriesCapitalsMap = new HashMap<>(); countriesCapitalsMap.put("Greece", "Athens"); countriesCapitalsMap.put("Spain", "Madrid"); countriesCapitalsMap.put("Italy", "Rome"); System.out.println("Initial Map:"); countriesCapitalsMap.entrySet().forEach(System.out::println); System.out.println(); // This will remove Athens and return true countriesCapitalsMap.remove("Greece","Athens"); // This will not remove Italy, since Italy maps to Rome countriesCapitalsMap.remove("Italy", "Venice"); System.out.println("Map after the 2 removals:"); countriesCapitalsMap.entrySet().forEach(System.out::println); System.out.println(); }
Output:
Initial Map: Greece=Athens Italy=Rome Spain=Madrid Map after the 2 removals: Italy=Rome Spain=Madrid
3.4.3 void clear()
The clear()
method just empties the HashMap.
public static void clear(){ /* clear() * Removes all the entries from a HashMap */ HashMap<String, String> countriesCapitalsMap = new HashMap<>(); countriesCapitalsMap.put("Greece", "Athens"); countriesCapitalsMap.put("Spain", "Madrid"); countriesCapitalsMap.put("Italy", "Rome"); countriesCapitalsMap.clear(); //This will print nothing as the HashMap is empty countriesCapitalsMap.entrySet().forEach(System.out::println); }
3.5 Miscellaneous methods
In this section, we will explain through examples all the methods that don’t have to do with adding, removing, or accessing the HashMap.
HashMap<String, String> countriesCapitalsMap = new HashMap<>(); countriesCapitalsMap.put("Greece", "Athens"); countriesCapitalsMap.put("Spain", "Madrid"); countriesCapitalsMap.put("Italy", "Rome"); /* containsKey(K key) * returns true if the key exists in the map */ System.out.println("Entry with key Greece exists?"); System.out.println(countriesCapitalsMap.containsKey("Greece")); System.out.println(); System.out.println("Entry with key Germany exists?"); System.out.println(countriesCapitalsMap.containsKey("Germany")); System.out.println(); /* containsValue(V key) * returns true if the value exists in the map */ System.out.println("Entry with value Athens exists?"); System.out.println(countriesCapitalsMap.containsValue("Athens")); System.out.println(); System.out.println("Entry with value Berlin exists?"); System.out.println(countriesCapitalsMap.containsValue("Berlin")); System.out.println(); /* isEmpty() * returns true if the HashMap has no entries */ // Will return false countriesCapitalsMap.isEmpty(); // Will return true new HashMap<>().isEmpty(); /* size() * returns the number of entries in the HashMap */ // Will return 3 countriesCapitalsMap.size(); // HashMap forEach countriesCapitalsMap.forEach((k,v) -> System.out.println("Key is: "+ k + ", Value is: " + v));
Output:
Entry with key Greece exists? true Entry with key Germany exists? false Entry with value Athens exists? true Entry with value Berlin exists? false Key is: Greece, Value is: Athens Key is: Italy, Value is: Rome Key is: Spain, Value is: Madrid
4. A Java HashMap example – Real-world use-case
Let’s say we have many sentences, and we want to count how many times each specific word occurred.
The first thing that should come to your mind, is using a HashMap, with the key being the word and the value being the number of times this word occurred.
Let’s go straight into the implementation and then we’ll explain everything.
import java.lang.reflect.Array; import java.util.*; import java.util.stream.Collectors; public class CountWords { public static final String SENTENCES = "I met an interesting turtle while the song on the radio blasted away." + "He loved eating his bananas in hot dog buns." + "I'm not a party animal, but I do like animal parties." + "The ice-cream trucks bring back bad memories for all of us." + "The bug was having an excellent day until he hit the windshield." + "I trust everything that's written in purple ink." + "If you really strain your ears, you can just about hear the sound of no one giving a damn." + "We have a lot of rain in June." + "He stomped on his fruit loops and thus became a cereal killer." + "This made him feel like an old-style rootbeer float smells."; public static void main(String[] args) { printWordsMap(SENTENCES); } public static void printWordsMap(String sentences){ // replacing punctuation marks with spaces as we don't want them to count as words, and then make every word lowercase sentences = sentences.replaceAll("[.,!?]").toLowerCase(); //split by space List<String> words = Arrays.asList(sentences.split("\\s")); //remove any space that might exist words = words.stream() .map(word -> word.replace(" ","")) .filter(word -> !word.equals("")) .collect(Collectors.toList()); //The map that we'll use HashMap<String, Integer> wordsMap = new HashMap<>(); words.forEach(word -> { //Before java 8 //if(wordsMap.containsKey(word)) // wordsMap.replace(word, wordsMap.get(word) + 1); //else // wordsMap.put(word,1); //using the getOrDefault //wordsMap.put(word, wordsMap.getOrDefault(word, 0) + 1); //using merge wordsMap.merge(word,1, Integer::sum); }); // Sort by value List <Map.Entry <String, Integer>> entries = new ArrayList<>(wordsMap.entrySet()); entries.sort(Map.Entry.comparingByValue(Comparator.reverseOrder())); //Print the result entries.forEach(entry -> System.out.println("The word \"" + entry.getKey() + "\" occurred " + entry.getValue() + " times")); } }
Let’s explain what happened here:
- In line 26, we replace all the punctuation marks as we don’t want them to count as words and also convert every character to lower case (e.g. we need the “The” word and the “the” word to count as the same word.
- In line 29, we split by a space, and we append the result to a list.
- In lines 32 – 35, we replace all the spaces that a word might have (we don’t want to count the “the ” and “the ” as different words).
- In line 40, we traverse through all words.
- In lines 44 – 47, if the map already contains the key, we get the number that this word has already occurred(this is the value of the mapping), and we add 1. If not, we insert a new entry ( word -> 1) as this word is not in the map.
- In line 50, there is another way to do what we did in 43 – 46. We put the new value in the map based on the result of
getOrDefault()
. If the word already exists, thegetOrDefault()
will return the times we have seen this word and add one. Otherwise, the default value will return (0) and then we add one. - In line 53, we use the java 8 merge method. As discussed before, the merge takes as parameters the key (word), the value to be associated with the old value to produce the new value (that is one since we want to add one each time we see the same word) and a function which will produce the new value (here is the sum, since we add the old value with one).
- In lines 58 – 59 we use the
comparingByValue()
method to sort the map by value (we want the most words with most occurrences to be on top). - In line 62, we print the result.
This is the output for the input provided in the code snippet. You can choose your own sentences and provide them as input and see the results.
The word "the" occurred 6 times The word "a" occurred 4 times The word "in" occurred 3 times The word "an" occurred 3 times The word "of" occurred 3 times The word "i" occurred 3 times The word "he" occurred 3 times The word "his" occurred 2 times The word "you" occurred 2 times The word "like" occurred 2 times The word "animal" occurred 2 times The word "on" occurred 2 times The word "but" occurred 1 times The word "bad" occurred 1 times The word "rootbeer" occurred 1 times The word "sound" occurred 1 times The word "about" occurred 1 times The word "bring" occurred 1 times The word "feel" occurred 1 times The word "your" occurred 1 times The word "do" occurred 1 times The word "float" occurred 1 times The word "while" occurred 1 times The word "him" occurred 1 times The word "radio" occurred 1 times The word "hit" occurred 1 times The word "loved" occurred 1 times The word "killer" occurred 1 times The word "written" occurred 1 times The word "trucks" occurred 1 times The word "if" occurred 1 times The word "day" occurred 1 times The word "stomped" occurred 1 times The word "us" occurred 1 times The word "strain" occurred 1 times The word "all" occurred 1 times The word "song" occurred 1 times The word "rain" occurred 1 times The word "having" occurred 1 times The word "smells" occurred 1 times The word "thus" occurred 1 times The word "turtle" occurred 1 times The word "excellent" occurred 1 times The word "made" occurred 1 times The word "this" occurred 1 times The word "ice-cream" occurred 1 times The word "cereal" occurred 1 times The word "parties" occurred 1 times The word "dog" occurred 1 times The word "party" occurred 1 times The word "trust" occurred 1 times The word "became" occurred 1 times The word "no" occurred 1 times The word "away" occurred 1 times The word "fruit" occurred 1 times The word "for" occurred 1 times The word "back" occurred 1 times The word "that's" occurred 1 times The word "bananas" occurred 1 times The word "giving" occurred 1 times The word "hot" occurred 1 times The word "we" occurred 1 times The word "i'm" occurred 1 times The word "lot" occurred 1 times The word "can" occurred 1 times The word "not" occurred 1 times The word "and" occurred 1 times The word "have" occurred 1 times The word "memories" occurred 1 times The word "everything" occurred 1 times The word "just" occurred 1 times The word "met" occurred 1 times The word "hear" occurred 1 times The word "old-style" occurred 1 times The word "one" occurred 1 times The word "ink" occurred 1 times The word "interesting" occurred 1 times The word "was" occurred 1 times The word "loops" occurred 1 times The word "eating" occurred 1 times The word "blasted" occurred 1 times The word "really" occurred 1 times The word "damn" occurred 1 times The word "ears" occurred 1 times The word "june" occurred 1 times The word "bug" occurred 1 times The word "buns" occurred 1 times The word "purple" occurred 1 times The word "until" occurred 1 times The word "windshield" occurred 1 times
5. Conclusion
By now, you should be able to use HashMap in Java in the most efficient way. You can find the source code over on our GitHub page.