Java Hashmap Tutorial

Avatar

By squashlabs, Last Updated: October 23, 2023

Java Hashmap Tutorial

Introduction to Hashmap

A HashMap is a data structure in Java that allows you to store and retrieve key-value pairs. It provides constant time complexity for basic operations like adding, removing, and retrieving elements. This makes it a popular choice for many applications where fast access to data is important.

Related Article: How To Parse JSON In Java

Structure of a Hashmap

A HashMap is internally implemented as an array of linked lists. Each element in the array is called a bucket, and each bucket contains a linked list of key-value pairs. When you add a key-value pair to a HashMap, it calculates the index of the bucket using the hash code of the key. If multiple keys have the same hash code, they are stored in the same bucket as a linked list.

Creating a Hashmap

To create a HashMap in Java, you need to import the java.util.HashMap class. Here’s an example of creating a HashMap and adding some key-value pairs:

import java.util.HashMap;

public class Main {
    public static void main(String[] args) {
        HashMap<String, Integer> hashMap = new HashMap<>();
        hashMap.put("apple", 10);
        hashMap.put("banana", 5);
        hashMap.put("orange", 8);
    }
}

In this example, we create a HashMap that stores String keys and Integer values. We then add three key-value pairs to the HashMap using the put() method.

Methods in Hashmap

HashMap provides various methods to manipulate and retrieve elements. Here are some commonly used methods:

put(key, value): Adds a key-value pair to the HashMap.
get(key): Retrieves the value associated with the specified key.
remove(key): Removes the key-value pair associated with the specified key.
containsKey(key): Checks if the HashMap contains a specific key.
containsValue(value): Checks if the HashMap contains a specific value.
size(): Returns the number of key-value pairs in the HashMap.

Related Article: How To Convert Array To List In Java

Adding Elements to a Hashmap

Adding elements to a HashMap is simple and efficient. You can use the put(key, value) method to add key-value pairs. Here’s an example:

HashMap<String, Integer> hashMap = new HashMap<>();
hashMap.put("apple", 10);
hashMap.put("banana", 5);
hashMap.put("orange", 8);

In this example, we add three key-value pairs to the HashMap. The keys are strings (“apple”, “banana”, “orange”) and the values are integers.

Removing Elements from a Hashmap

Removing elements from a HashMap can be done using the remove(key) method. Here’s an example:

HashMap<String, Integer> hashMap = new HashMap<>();
hashMap.put("apple", 10);
hashMap.put("banana", 5);
hashMap.put("orange", 8);

hashMap.remove("banana");

In this example, we remove the key-value pair with the key “banana” from the HashMap.

Accessing Elements in a Hashmap

You can access elements in a HashMap using the get(key) method. Here’s an example:

HashMap<String, Integer> hashMap = new HashMap<>();
hashMap.put("apple", 10);
hashMap.put("banana", 5);
hashMap.put("orange", 8);

int appleQuantity = hashMap.get("apple");
System.out.println(appleQuantity); // Output: 10

In this example, we retrieve the value associated with the key “apple” and store it in the appleQuantity variable.

Related Article: How To Iterate Over Entries In A Java Map

Looping Through a Hashmap

You can iterate over the key-value pairs in a HashMap using various methods. Here’s an example using a for-each loop:

HashMap<String, Integer> hashMap = new HashMap<>();
hashMap.put("apple", 10);
hashMap.put("banana", 5);
hashMap.put("orange", 8);

for (String key : hashMap.keySet()) {
    int value = hashMap.get(key);
    System.out.println(key + ": " + value);
}

In this example, we loop through each key in the HashMap using the keySet() method. We retrieve the corresponding value using the get(key) method and print both the key and value.

Use Case: Storing User Information

HashMaps are often used to store user information in web applications. Here’s an example of using a HashMap to store user details:

HashMap<Integer, User> userMap = new HashMap<>();

// Creating user objects
User user1 = new User(1, "John");
User user2 = new User(2, "Jane");

// Adding users to the HashMap
userMap.put(user1.getId(), user1);
userMap.put(user2.getId(), user2);

// Retrieving a user by ID
User retrievedUser = userMap.get(1);
System.out.println(retrievedUser.getName()); // Output: John

In this example, we have a User class that represents a user with an ID and a name. We create two user objects and store them in the HashMap using their IDs as keys. We can then retrieve a user object by its ID.

Use Case: Counting Word Frequency

HashMaps can also be used to count the frequency of words in a text. Here’s an example:

String text = "This is a sample text. This text contains some words. Some words may repeat.";

HashMap<String, Integer> wordFrequencyMap = new HashMap<>();
String[] words = text.split(" ");

for (String word : words) {
    wordFrequencyMap.put(word, wordFrequencyMap.getOrDefault(word, 0) + 1);
}

for (String word : wordFrequencyMap.keySet()) {
    int frequency = wordFrequencyMap.get(word);
    System.out.println(word + ": " + frequency);
}

In this example, we split the text into an array of words using the split() method. We then iterate over each word, adding it to the HashMap and incrementing its count. Finally, we loop through the HashMap and print the word and its frequency.

Related Article: How To Split A String In Java

Best Practice: Using Generics

It is considered a best practice to use generics when working with HashMaps to ensure type safety. Here’s an example:

HashMap<String, Integer> hashMap = new HashMap<>();

In this example, we specify that the keys of the HashMap are strings and the values are integers. This allows the compiler to enforce type safety and prevents runtime errors.

Best Practice: Avoiding Null Keys and Values

It is generally recommended to avoid using null as keys or values in a HashMap. While it is technically allowed, it can lead to unexpected behavior and null pointer exceptions. Instead, consider using sentinel values or redesigning your code to handle such scenarios more robustly.

Real World Example: Implementing a Phone Directory

A real-world example of using a HashMap is implementing a phone directory. Here’s an example:

HashMap<String, String> phoneDirectory = new HashMap<>();

phoneDirectory.put("John Smith", "555-1234");
phoneDirectory.put("Jane Doe", "555-5678");

String johnsNumber = phoneDirectory.get("John Smith");
System.out.println(johnsNumber); // Output: 555-1234

In this example, we use a HashMap to store names as keys and phone numbers as values. We can easily retrieve a phone number by providing the name.

Related Article: How To Convert Java Objects To JSON With Jackson

Real World Example: Creating a Shopping Cart

Another real-world example of using a HashMap is creating a shopping cart. Here’s an example:

HashMap<String, Integer> shoppingCart = new HashMap<>();

// Adding items to the shopping cart
shoppingCart.put("Apple", 2);
shoppingCart.put("Banana", 3);
shoppingCart.put("Orange", 1);

// Updating the quantity of an item
shoppingCart.put("Apple", shoppingCart.getOrDefault("Apple", 0) + 1);

// Removing an item from the shopping cart
shoppingCart.remove("Banana");

// Retrieving the total number of items in the shopping cart
int totalItems = shoppingCart.values().stream().mapToInt(Integer::intValue).sum();
System.out.println(totalItems); // Output: 6

In this example, we use a HashMap to store items as keys and quantities as values. We can easily add, update, and remove items from the shopping cart. We can also calculate the total number of items in the cart by summing up the quantities.

Performance Consideration: Initial Capacity and Load Factor

When creating a HashMap, you can specify an initial capacity and a load factor. The initial capacity is the number of buckets created when the HashMap is constructed. The load factor determines when the HashMap is resized. It is a value between 0 and 1, where 1 means the HashMap is resized when it is 100% full. Adjusting these parameters can impact the performance of the HashMap based on the expected number of key-value pairs and the rate of growth.

Performance Consideration: Hashing Function

The performance of a HashMap is heavily dependent on the quality of the hashing function used to calculate the index of the bucket. A good hashing function distributes the keys evenly across the buckets, reducing collisions and improving performance. Java’s built-in hashing function for objects calculates the hash code based on the memory address of the object, but you can override this behavior by implementing the hashCode() method in your key objects.

Related Article: Storing Contact Information in Java Data Structures

Advanced Technique: Custom Key Objects

By default, HashMap uses the hashCode() and equals() methods of the key objects to determine equality and calculate the bucket index. If you want to use custom objects as keys, you need to override these methods to ensure correct behavior. Here’s an example:

class Person {
    private String name;
    private int age;

    // constructor, getters, setters

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }
        Person person = (Person) obj;
        return age == person.age && Objects.equals(name, person.name);
    }
}

In this example, we override the hashCode() and equals() methods in the Person class to ensure that two Person objects with the same name and age are considered equal.

Advanced Technique: Concurrent Access

If multiple threads access a HashMap concurrently, there may be synchronization issues and data inconsistencies. Java provides a synchronized version of HashMap called ConcurrentHashMap, which ensures thread-safety and handles concurrent access gracefully. If you need to work with concurrent access, consider using ConcurrentHashMap instead.

Code Snippet: Insertion of Elements

Here’s a code snippet demonstrating the insertion of elements into a HashMap:

HashMap<String, Integer> hashMap = new HashMap<>();
hashMap.put("apple", 10);
hashMap.put("banana", 5);
hashMap.put("orange", 8);

In this example, we create a HashMap and add three key-value pairs using the put() method.

Related Article: How to Convert JSON String to Java Object

Code Snippet: Deletion of Elements

Here’s a code snippet demonstrating the deletion of elements from a HashMap:

HashMap<String, Integer> hashMap = new HashMap<>();
hashMap.put("apple", 10);
hashMap.put("banana", 5);
hashMap.put("orange", 8);

hashMap.remove("banana");

In this example, we remove the key-value pair with the key “banana” from the HashMap using the remove() method.

Code Snippet: Retrieval of Elements

Here’s a code snippet demonstrating the retrieval of elements from a HashMap:

HashMap<String, Integer> hashMap = new HashMap<>();
hashMap.put("apple", 10);
hashMap.put("banana", 5);
hashMap.put("orange", 8);

int appleQuantity = hashMap.get("apple");
System.out.println(appleQuantity); // Output: 10

In this example, we retrieve the value associated with the key “apple” using the get() method.

Code Snippet: Iterating over Entries

Here’s a code snippet demonstrating how to iterate over the key-value pairs in a HashMap:

HashMap<String, Integer> hashMap = new HashMap<>();
hashMap.put("apple", 10);
hashMap.put("banana", 5);
hashMap.put("orange", 8);

for (Map.Entry<String, Integer> entry : hashMap.entrySet()) {
    String key = entry.getKey();
    int value = entry.getValue();
    System.out.println(key + ": " + value);
}

In this example, we use the entrySet() method to obtain a set of key-value pairs. We then iterate over each entry and retrieve the key and value.

Related Article: How to Retrieve Current Date and Time in Java

Code Snippet: Sorting Hashmap by Keys or Values

Here’s a code snippet demonstrating how to sort a HashMap by keys or values:

Sorting by keys:

HashMap<String, Integer> hashMap = new HashMap<>();
hashMap.put("apple", 10);
hashMap.put("banana", 5);
hashMap.put("orange", 8);

TreeMap<String, Integer> sortedMap = new TreeMap<>(hashMap);
for (Map.Entry<String, Integer> entry : sortedMap.entrySet()) {
    String key = entry.getKey();
    int value = entry.getValue();
    System.out.println(key + ": " + value);
}

Sorting by values:

HashMap<String, Integer> hashMap = new HashMap<>();
hashMap.put("apple", 10);
hashMap.put("banana", 5);
hashMap.put("orange", 8);

List<Map.Entry<String, Integer>> sortedList = new ArrayList<>(hashMap.entrySet());
sortedList.sort(Map.Entry.comparingByValue());
for (Map.Entry<String, Integer> entry : sortedList) {
    String key = entry.getKey();
    int value = entry.getValue();
    System.out.println(key + ": " + value);
}

In both examples, we use a TreeMap to sort the HashMap by keys or a sorted list to sort by values. We then iterate over the sorted entries and print the key-value pairs.

Error Handling: Null Pointer Exceptions

When working with HashMaps, you need to be mindful of null keys and null values. If you try to access a non-existent key or value, a null pointer exception may occur. To avoid this, you can use the containsKey(key) or containsValue(value) methods to check if a key or value exists before accessing it.

Error Handling: Concurrent Modification Exceptions

If you modify a HashMap while iterating over it using an iterator, a concurrent modification exception may occur. To avoid this, consider using the Iterator or ListIterator methods provided by the keySet(), entrySet(), or values() methods to safely iterate over the HashMap.

This concludes the Java HashMap tutorial. You have learned about the basics of HashMap, its structure, methods, and various use cases. You have also explored best practices, performance considerations, advanced techniques, code snippets, and error handling.

How to Generate Random Integers in a Range in Java

Generating random integers within a specific range in Java is made easy with the Random class. This article explores the usage of java.util.Random and ThreadLocalRandom... read more

How to Reverse a String in Java

This article serves as a guide on reversing a string in Java programming language. It explores two main approaches: using a StringBuilder and using a char array.... read more

Java Equals Hashcode Tutorial

Learn how to implement equals and hashcode methods in Java. This tutorial covers the basics of hashcode, constructing the equals method, practical use cases, best... read more

How To Convert String To Int In Java

How to convert a string to an int in Java? This article provides clear instructions using two approaches: Integer.parseInt() and Integer.valueOf(). Learn the process and... read more

Java Composition Tutorial

This tutorial: Learn how to use composition in Java with an example. This tutorial covers the basics of composition, its advantages over inheritance, and best practices... read more

Popular Data Structures Asked in Java Interviews

Tackle Java interview questions on popular data structures with this in-depth explanation. Learn about arrays, linked lists, stacks, queues, binary trees, hash tables,... read more