In the realm of Java programming, data structures play a vital role in efficiently organizing and manipulating data. One such indispensable data structure is the Java HashMap
. With its powerful capabilities and versatile nature, HashMaps have become a cornerstone of Java development. In this blog, we will explore what the Java HashMap
is, including coding examples, their benefits, and potential disadvantages.
A Java HashMap
stores key-value pairs where each key is different. This makes it easier and faster to find the value.
It achieves efficient storage and retrieval of key-value pairs by combining hash tables and linked lists in its back-end implementation. Let's dive into the details.
Buckets and Hashing
The HashMap
internally uses an array of buckets to store the elements.
Each bucket is capable of holding multiple elements because of possible hash collisions. Note that collisions can happen when multiple keys have the same code.
The value for the key (i.e., the hash code) is calculated using the hashCode()
method whenever a key-value pair is added to the HashMap
. The value of the key is used to determine the specific bucket where the element will be added in the list.
Java’s hashCode()
function spreads the hash codes uniformly across the array to minimize collisions and improve performance.
Linked list nodes
Each bucket in the HashMap
is basically a linked list of nodes.
Whenever two items have the same code and need to go in the same bucket (otherwise known as a collision), we just add the new items to the front of that list.
In the linked list, each node holds both the key-value information and a reference to the next node that comes after it in the list.
Load factor and rehashing
The HashMap
maintains a load factor that represents the ratio of filled buckets to the total number of buckets.
When the load factor exceeds a certain threshold (the default is 0.75), the HashMap
automatically increases the size of the underlying bucket array and hashes all the elements again. This process is called rehashing.
Rehashing involves creating a new array with a larger capacity, recalculating the hash codes for all the keys, and redistributing the elements across the new array. This helps maintain a balanced distribution of elements and keeps the average bucket size small, improving performance.
Let’s take a look at some code examples to better understand how the Java HashMap
works.
put(key, value)
: The function adds a key-value pair to the HashMap
. If the key is already there, it simply updates its associated value with the new one.
import java.util.HashMap;public class main {public static void main(String[] args) {// Creating a HashMapHashMap<String, Integer> studentScores = new HashMap<>();// Adding key-value pairsstudentScores.put("John", 95);studentScores.put("Emily", 87);studentScores.put("Michael", 92);System.out.println(studentScores);//updating John's score.//Note that the key "John" already exists.//The score is simply updatedstudentScores.put("John", 85);System.out.println(studentScores);}}
get(key)
: This retrieves the value associated with the specified key. If the key is not found, it returns null
.
import java.util.HashMap;public class main {public static void main(String[] args) {// Creating a HashMapHashMap<String, Integer> studentScores = new HashMap<>();// Adding key-value pairsstudentScores.put("John", 95);studentScores.put("Emily", 87);studentScores.put("Michael", 92);// Retrieving a value using a keyint johnScore = studentScores.get("John");System.out.println("John's score: " + johnScore);}}
containsKey(key)
: This checks if the HashMap
contains a specific key. It returns true
if the key is present; otherwise, it returns false
.
import java.util.HashMap;public class main {public static void main(String[] args) {// Creating a HashMapHashMap<String, Integer> studentScores = new HashMap<>();// Adding key-value pairsstudentScores.put("John", 95);studentScores.put("Emily", 87);studentScores.put("Michael", 92);// Checking if a key existsboolean containsEmily = studentScores.containsKey("Emily");System.out.println("Contains Emily? " + containsEmily);}}
containsValue(value)
: This checks if the HashMap
contains a specific value. It returns true
if the value is present; otherwise, it returns false
.
import java.util.HashMap;public class main {public static void main(String[] args) {// Creating a HashMapHashMap<String, Integer> studentScores = new HashMap<>();// Adding key-value pairsstudentScores.put("John", 95);studentScores.put("Emily", 87);studentScores.put("Michael", 92);// Checking if a value existsboolean containsScore92 = studentScores.containsValue(92);System.out.println("Contains score 92? " + containsScore92);}}
remove(key)
: This removes the key-value pair associated with the specified key from the HashMap
. It returns the value that was removed, or null
if the key was not found.
import java.util.HashMap;public class main {public static void main(String[] args) {// Creating a HashMapHashMap<String, Integer> studentScores = new HashMap<>();// Adding key-value pairsstudentScores.put("John", 95);studentScores.put("Emily", 87);studentScores.put("Michael", 92);// Removing a key-value pairInteger removedScore = studentScores.remove("Michael");System.out.println("Removed score: " + removedScore);}}
size()
: This returns the number of key-value pairs currently stored in the HashMap
.
import java.util.HashMap;public class main {public static void main(String[] args) {// Creating a HashMapHashMap<String, Integer> studentScores = new HashMap<>();// Adding key-value pairsstudentScores.put("John", 95);studentScores.put("Emily", 87);studentScores.put("Michael", 92);System.out.println("Size of the HashMap: " + studentScores.size());}}
isEmpty()
: This checks if the HashMap
is empty and returns true
if the HashMap
contains no elements; otherwise, it returns false
.
import java.util.HashMap;import java.util.Set;public class main {public static void main(String[] args) {// Creating a HashMapHashMap<String, Integer> studentScores = new HashMap<>();// Adding key-value pairsstudentScores.put("John", 95);studentScores.put("Emily", 87);studentScores.put("Michael", 92);// Retrieving all the keysSystem.out.println("Is HashMap empty? " + studentScores.isEmpty());}}
keySet()
: This returns a set containing all the keys in the HashMap
.
import java.util.HashMap;import java.util.Set;public class main {public static void main(String[] args) {// Creating a HashMapHashMap<String, Integer> studentScores = new HashMap<>();// Adding key-value pairsstudentScores.put("John", 95);studentScores.put("Emily", 87);studentScores.put("Michael", 92);// Retrieving all the keysSet<String> keys = studentScores.keySet();System.out.println("Keys in the HashMap: " + keys);}}
values()
: This returns a collection containing all the values in the HashMap
.
import java.util.HashMap;import java.util.Collection;public class main {public static void main(String[] args) {// Creating a HashMapHashMap<String, Integer> studentScores = new HashMap<>();// Adding key-value pairsstudentScores.put("John", 95);studentScores.put("Emily", 87);studentScores.put("Michael", 92);// Retrieving all the valuesCollection<Integer> values = studentScores.values();System.out.println("Values in the HashMap: " + values);}}
entrySet()
: This returns a set containing all the key-value pairs (entries) in the HashMap
.
import java.util.HashMap;import java.util.Set;public class main {public static void main(String[] args) {// Creating a HashMapHashMap<String, Integer> studentScores = new HashMap<>();// Adding key-value pairsstudentScores.put("John", 95);studentScores.put("Emily", 87);studentScores.put("Michael", 92);// Retreiving all entiesSet<HashMap.Entry<String, Integer>> entries = studentScores.entrySet();System.out.println("Entries in the HashMap: " + entries);}}
clear()
: This removes all the key-value pairs from the HashMap
, making it empty.
import java.util.HashMap;import java.util.Set;public class main {public static void main(String[] args) {// Creating a HashMapHashMap<String, Integer> studentScores = new HashMap<>();// Adding key-value pairsstudentScores.put("John", 95);studentScores.put("Emily", 87);studentScores.put("Michael", 92);// Clearing the HashMapstudentScores.clear();System.out.println("HashMap cleared. Size: " + studentScores.size());}}
Note: HashMaps do not guarantee any specific order of elements. If there is a need to maintain a specific order, the
LinkedHashMap
class can be considered instead.
The following table summarizes the time complexities of the functions mentioned above found in the official
Operation | Time Complexity |
| O(1) average–O(n) worst case |
| O(1) average–O(n) worst case |
| O(1) average–O(n) worst case |
| O(n) |
| O(1) average–O(n) worst case |
| O(1) |
| O(1) |
| O(n) |
| O(n) |
| O(n) |
| O(1) |
Note that the HashMap
class offers additional methods and functionalities that can be explored in the official
To iterate over a HashMap
, there are various approaches that can be chosen.
import java.util.HashMap;import java.util.Iterator;public class HashMapIterationExample {public static void main(String[] args) {// Create a HashMapHashMap<String, Integer> studentScores = new HashMap<>();// Add elements to the HashMapstudentScores.put("John", 95);studentScores.put("Emily", 87);studentScores.put("Michael", 92);// Iterating using EntrySet()System.out.println("Iterating using EntrySet():");for (HashMap.Entry<String, Integer> entry : studentScores.entrySet()) {String key = entry.getKey();Integer value = entry.getValue();System.out.println("Key: " + key + ", Value: " + value);}// Iterating using KeySet()System.out.println("\nIterating using KeySet():");for (String key : studentScores.keySet()) {Integer value = studentScores.get(key);System.out.println("Key: " + key + ", Value: " + value);}// Iterating using IteratorSystem.out.println("\nIterating using Iterator:");Iterator<HashMap.Entry<String, Integer>> iterator = studentScores.entrySet().iterator();while (iterator.hasNext()) {HashMap.Entry<String, Integer> entry = iterator.next();String key = entry.getKey();Integer value = entry.getValue();System.out.println("Key: " + key + ", Value: " + value);}}}
In the example above, we create a class called HashMapIterationExample
containing a main
method. The necessary classes, HashMap
and Iterator
from the java.util
package, are imported.
Inside the main
method, we create a HashMap<String, Integer>
called studentScores
and add some key-value pairs to it.
The different ways to iterate over the HashMaps are as follows:
Lines 15–20: In this approach, the entrySet()
method returns a set of key-value pairs (Map.Entry
) in the HashMap. The for-each loop then iterates over each entry, allowing access to the key via getKey()
, and the value via getValue()
.
Lines 23–27: The keySet()
method returns a set of keys present in the HashMap
. We can then use each key to retrieve the corresponding value using the get(key)
method.
Lines 30–37: This approach involves obtaining an iterator using entrySet().iterator()
and then iterating over the HashMap
using a while loop. Similar to the first method, the key and the value can be accessed using getKey()
and getValue()
, respectively.
What is the Java HashMap? The Java HashMap
is a popular and powerful data structure in the Java programming language. However, when working with other programming languages, we have some equivalent data structures to choose from.
In Python, the data structure equivalent to a Java HashMap
is the dictionary, which allows us to store key-value pairs where keys are unique and values can be of any type.
In C++, the unordered_map
from the Standard Template Library (STL) provides a functionality similar to that of a HashMap
. It offers fast insertion, retrieval, and deletion operations.
In JavaScript, objects can be used as data structures similar to HashMap
. Keys can be strings or symbols, and values can be of any type.
Below is an example of the codes in C++, Python, and JavaScript.
#include <iostream>#include <unordered_map>int main() {// Creating an unordered_mapstd::unordered_map<std::string, int> student_scores = {{"John", 95},{"Emily", 87},{"Michael", 92}};// Accessing a value using a keyint john_score = student_scores["John"];std::cout << "John's score: " << john_score << std::endl;// Updating a valuestudent_scores["Emily"] = 90;// Removing a key-value pairstudent_scores.erase("Michael");return 0;}
Let’s look at the advantages of using HashMap
.
Fast retrieval | It offers constant-time performance for basic operations such as insertion, retrieval, and deletion, making them highly efficient for handling large datasets. |
Flexible key-value pairing | It allows the association of any object as a key and any object as a value, enabling developers to create custom data structures for specific use cases. |
No duplicate keys | It enforces uniqueness of keys, ensuring that no duplicate keys exist within the collection. |
Dynamic sizing | It automatically adjusts their size to accommodate more elements, eliminating the need for manual resizing. |
While HashMap
provides numerous advantages, it’s essential to be aware of its potential limitations.
No preserved order | It does not guarantee any particular order of elements. If we require ordered key-value pairs, we need to consider using a |
Null key limitation | It allows a single null key but can't have duplicate null keys. |
Hash collision performance | In rare cases, different keys may hash to the same index, resulting in a collision. This situation can degrade performance, especially when dealing with a large number of collisions. However, Java's |
Thread safety | It is not inherently thread-safe. If the application involves multiple threads accessing or modifying the map concurrently, we need to use |
The Java HashMap
offers a powerful and efficient way to store, retrieve, and manipulate data using key-value pairs. With its flexibility and high performance, it has become an indispensable tool for Java developers. By understanding the benefits and potential limitations of the HashMap
, its strengths can be leveraged to create robust and efficient applications.
We hope this experience was fun and helped you learn about HashMap
in Java. If you are looking to explore other data types and how they are used in different programming languages, we recommend checking out the following Educative courses:
Learn to Code: Java for Absolute Beginners
Java is a high-level, object-oriented language known for its portability and reliability. Mastering Java is key for developers to build scalable, secure software efficiently. In this course, you will start by mastering the art of problem-solving with simple Java programs, such as the Bottle Filling example. You will learn how to structure your solutions, create execution sheets, and enhance your problem-solving abilities through practical exercises and quizzes. Progressing further, you will learn decision-making and branching in Java, understanding flowcharts, conditional expressions, and their application. You will also learn about Java basics, including the first Java program, fundamentals, conditional statements, and error categories, followed by in-depth lessons on working with Java strings and arrays. By the end of this course, you will have a solid understanding of Java programming fundamentals and the ability to solve real-world problems using Java.
Learn C++: The Complete Course for Beginners
If you're a beginner and want to learn C++ to start your coding journey, you're in the right place. This comprehensive course starts from the absolute basics and gradually builds up to exciting real-life coding projects. The emphasis throughout is on practical lessons and analogies that you can relate to. As you learn, you'll work your way through dozens of coding exercises that you can run from right inside your browser. By the time you're done, you'll have a strong grasp of C++, one of the most in-demand programming languages in the world. You'll have gotten plenty of hands-on practice and will be able to confidently write your own applications.
Python 3: From Beginner to Advanced
In this course, you will get a comprehensive overview of Python. You will start by laying the foundation and learning the introductory topics like operators, conditional statements, functions, loops, assignment statements, and more. You will then move onto more advanced topics such as classes and inheritance, iterators, list comprehensions, and dictionaries. Along with this, you will also get to explore the concept of testing and take a look at how GUI applications can be designed using Tkinter, Python's standard GUI library. By the time you're done, you'll be able to hit the ground running and be equipped with the tools that will allow you to be productive in Python.
Free Resources