Home/Blog/Programming/What is a HashMap in Java?
Home/Blog/Programming/What is a HashMap in Java?

What is a HashMap in Java?

Kamran Lodhi
Dec 20, 2023
6 min read

Become a Software Engineer in Months, Not Years

From your first line of code, to your first day on the job — Educative has you covered. Join 2M+ developers learning in-demand programming skills.

Introduction#

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.

Java HashMap: Behind the scenes#

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.

An array of buckets storing elements
An array of buckets storing 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.

Linked list of nodes
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.

Implementing different HashMap functions#

Let’s take a look at some code examples to better understand how the Java HashMap works.

HashMap in Java
HashMap in Java

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 HashMap
HashMap<String, Integer> studentScores = new HashMap<>();
// Adding key-value pairs
studentScores.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 updated
studentScores.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 HashMap
HashMap<String, Integer> studentScores = new HashMap<>();
// Adding key-value pairs
studentScores.put("John", 95);
studentScores.put("Emily", 87);
studentScores.put("Michael", 92);
// Retrieving a value using a key
int 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 HashMap
HashMap<String, Integer> studentScores = new HashMap<>();
// Adding key-value pairs
studentScores.put("John", 95);
studentScores.put("Emily", 87);
studentScores.put("Michael", 92);
// Checking if a key exists
boolean 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 HashMap
HashMap<String, Integer> studentScores = new HashMap<>();
// Adding key-value pairs
studentScores.put("John", 95);
studentScores.put("Emily", 87);
studentScores.put("Michael", 92);
// Checking if a value exists
boolean 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 HashMap
HashMap<String, Integer> studentScores = new HashMap<>();
// Adding key-value pairs
studentScores.put("John", 95);
studentScores.put("Emily", 87);
studentScores.put("Michael", 92);
// Removing a key-value pair
Integer 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 HashMap
HashMap<String, Integer> studentScores = new HashMap<>();
// Adding key-value pairs
studentScores.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 HashMap
HashMap<String, Integer> studentScores = new HashMap<>();
// Adding key-value pairs
studentScores.put("John", 95);
studentScores.put("Emily", 87);
studentScores.put("Michael", 92);
// Retrieving all the keys
System.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 HashMap
HashMap<String, Integer> studentScores = new HashMap<>();
// Adding key-value pairs
studentScores.put("John", 95);
studentScores.put("Emily", 87);
studentScores.put("Michael", 92);
// Retrieving all the keys
Set<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 HashMap
HashMap<String, Integer> studentScores = new HashMap<>();
// Adding key-value pairs
studentScores.put("John", 95);
studentScores.put("Emily", 87);
studentScores.put("Michael", 92);
// Retrieving all the values
Collection<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 HashMap
HashMap<String, Integer> studentScores = new HashMap<>();
// Adding key-value pairs
studentScores.put("John", 95);
studentScores.put("Emily", 87);
studentScores.put("Michael", 92);
// Retreiving all enties
Set<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 HashMap
HashMap<String, Integer> studentScores = new HashMap<>();
// Adding key-value pairs
studentScores.put("John", 95);
studentScores.put("Emily", 87);
studentScores.put("Michael", 92);
// Clearing the HashMap
studentScores.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 Java documentationOracle. 2019. “HashMap (Java Platform SE 8 ).” Oracle.com. September 11, 2019. https://docs.oracle.com/javase/8/docs/api/java/util/HashMap.html..

Operation

Time Complexity

put(key, value)

O(1) average–O(n) worst case

get(key)

O(1) average–O(n) worst case

containsKey(key)

O(1) average–O(n) worst case

containsValue(value)

O(n)

remove(key)

O(1) average–O(n) worst case

size()

O(1)

isEmpty()

O(1)

keySet()

O(n)

values()

O(n)

entrySet()

O(n)

clear()

O(1)


Note that the HashMap class offers additional methods and functionalities that can be explored in the official Java documentationOracle. 2019. “HashMap (Java Platform SE 8 ).” Oracle.com. September 11, 2019. https://docs.oracle.com/javase/8/docs/api/java/util/HashMap.html. to fully leverage the power of this data structure in Java programs.

Iterating over a Java HashMap#

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 HashMap
HashMap<String, Integer> studentScores = new HashMap<>();
// Add elements to the HashMap
studentScores.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 Iterator
System.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.

Data structures equivalent to Java HashMap in different programming languages#

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.

Data structures equivalent to a HashMap in other programming languages
Data structures equivalent to a HashMap in other programming languages

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_map
std::unordered_map<std::string, int> student_scores = {
{"John", 95},
{"Emily", 87},
{"Michael", 92}
};
// Accessing a value using a key
int john_score = student_scores["John"];
std::cout << "John's score: " << john_score << std::endl;
// Updating a value
student_scores["Emily"] = 90;
// Removing a key-value pair
student_scores.erase("Michael");
return 0;
}
HashMap-equivalent code in C++

Advantages of HashMap#

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.

Disadvantages of HashMap#

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 LinkedHashMap instead.

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 HashMap implementation uses techniques like separate chaining and balanced trees to handle collisions efficiently.

Thread safety

It is not inherently thread-safe. If the application involves multiple threads accessing or modifying the map concurrently, we need to use ConcurrentHashMap, which provides thread-safe operations without the need for external synchronization.

Conclusion and next steps#

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

Cover
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.

8hrs
Beginner
4 Challenges
6 Quizzes

Learn C++: The Complete Course for Beginners

Cover
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.

10hrs
Beginner
33 Challenges
67 Quizzes

Python 3: From Beginner to Advanced

Cover
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.

4hrs
Beginner
7 Challenges
7 Quizzes

  

Free Resources