HashMap in Kotlin

Learn via video courses
Topics Covered

Overview

A HashMap is an integral part of the Java collection framework and resides within java.util package. It serves as an implementation of the Map interface, which stores the data in the form of key-value pairs. It is similar to an array but with a dynamic size. One object is used as a key (index) to another object (value). The flexibility of HashMap lies in its ability to store various types of data. It can accommodate both objects and primitives as keys and values. This versatility allows developers to use diverse data types, providing a broad spectrum of possibilities in its applications.

HashMap Syntax and Declaration

A HashMap in Kotlin is a collection that stores key-value pairs. Each key in the HashMap must be unique, while the value can be duplicated. The HashMap class includes methods for adding, removing, and retrieving elements, as well as checking whether a key or value is present in the map.

Syntax

The syntax to use HashMap in Kotlin is:

KeywordDescription
valval is a keyword in Kotlin used to declare a read-only (immutable) property or local variable. Once a val is assigned, it cannot be reassigned.
myHashMapThis is the name of the variable. It's a user-defined identifier that refers to the HashMap instance. You can use this name to access and manipulate the HashMap throughout your code.
hashMapOf<>This is a function used to create a HashMap. It initializes and returns a new HashMap object with specified key-value types.
KeyTypeReplace this with the type of data you want to use as keys in the HashMap. For example, if you want the keys to be strings, you'd replace KeyType with String. Keys are used to retrieving corresponding values within the HashMap.
ValueTypeReplace this with the type of data you want to use as values in the HashMap. For example, if you want the values to be integers, you'd replace ValueType with Int. Values are the associated data stored within the HashMap and are accessed using their respective keys.

Common HashMap Operations

Here are some common operations that you can perform on a HashMap in Kotlin:

  1. Creating a HashMap: You can create a HashMap using the hashMapOf() function or the HashMap() constructor.
  1. Adding Elements: You can add elements to a HashMap using the put() function.
  1. Removing Elements: You can remove elements from a HashMap using the remove() function.
  1. Accessing Elements: You can access elements in a HashMap using their keys or get method.
  1. Checking if a Key is Present: You can check if a key is present in a HashMap using the containsKey() function.
  1. Checking if a Value is Present: You can check if a value is present in a HashMap using the containsValue() function.
  1. Getting the Size of the HashMap: You can get the size of a HashMap (i.e., the number of key-value pairs it contains) using the size property.
  1. Removing All Elements: You can remove all elements from a HashMap using the clear() function.

Iterating Over a HashMap

Iterating over a HashMap in Kotlin can be done using various methods, such as loops or built-in functions. Let's discuss each method with the example:

  1. Using a for loop:

This method uses a for loop to iterate over the entries in the HashMap. The (key, value) in the loop is a destructuring declaration that splits the Map.Entry object returned by the iterator into two variables key and value. This is a concise and readable way to iterate over a HashMap.

  1. Using forEach:

This method uses the forEach function provided by Kotlin’s standard library. It takes a lambda function as an argument, which is executed for each entry in the HashMap. The lambda function has two parameters, key, and value, which are automatically assigned with the key and value of each entry.

  1. Using an Iterator:

In this method, we create an iterator that traverses the keys of the HashMap. The hasNext() function checks whether there are any more keys in the HashMap and returns the next one. Then, we use the corresponding key to get the HashMap value. This method is more verbose in Kotlin and is not as idiomatic. However, it can be helpful in some cases where you need to control the iteration.

HashMap vs. Other Data Structures

Here's the comparison of HashMap with other Data Structures:

FeatureHashMapArrayListSetTreeMap
Storage StructureHashMaps are implemented using the HashMap class, which uses a hash function to map keys to indices in an array, also known as buckets, where the actual values are stored.Arrays are fixed-sized, contiguous blocks of memory that linearly store elements.A list is an ordered collection (also known as a sequence) where the user has precise control over where each element is inserted in the list.A Set is an unordered collection of objects that does not allow duplicate values to be stored. It is an extension of the Collection interface.TreeMap is implemented based on the red-black tree structure. It stores map elements in a Red-Black tree, which is a Self-Balancing Binary Search Tree.
Access MethodYou have to call hashmap.get(key) to retrieve a desired value.Each element in an array can be accessed by its index.Each element in a List can be accessed by its index.Elements in a Set can be iterated, but they cannot be accessed using a key.You have to call treemap.get(key) to retrieve a desired value.
OrderHashMap does not guarantee which order will be executed.Arrays will maintain your order, and you can sort them.Lists will maintain your order, and you can sort them.Set does not guarantee the order of elements.TreeMap is a type of SortedMap that allows you to sort the keys, and when you iterate over them, you can expect that they will be in order.
Time Complexity (Average Case)Access, Insertion, Deletion: O(1)O(1); Search: O(n)O(n)Access, Search, Insertion, Deletion: O(n)O(n)Access, Search, Insertion, Deletion: O(n)O(n)Access, Search, Insertion, Deletion: O(1)O(1)Access, Search, Insertion, Deletion: O(logn)O(log n)
Time Complexity (Worst Case)Access, Insertion, Deletion, Search: O(n)O(n)Access, Search, Insertion, Deletion: O(n)O(n)Access, Search, Insertion, Deletion: O(n)O(n)Access, Search, Insertion, Deletion: O(n)O(n)Access, Search, Insertion, Deletion: O(logn)O(log n)

Concurrency and Thread Safety

HashMap in Kotlin is not thread-safe by default. Therefore, if multiple threads try to access and change a HashMap at the same time, the results may be unpredictable and result in data inconsistencies. There are two ways to handle concurrent access in Kotlin.

  • Concurrent HashMap: This is a thread-safe implementation of the Map interface. It achieves thread safety by dividing the map into segments and locking only the relevant segment during write operations. This allows high concurrency levels during read operations.
  • Synchronized HashMap: For synchronizing a HashMap, you can use the Collections.synchronizedMap() method. This method returns a synchronized (thread-safe) map based on the specified map. It’s important to note that iteration over a synchronized map needs to be synchronized on the map itself to avoid non-deterministic behavior.

Practical Examples

  1. User Authentication:

Code:

Output:

Explanation: In the above example, a HashMap is used to store user credentials for authentication purposes. The UserAuthenticator class manages the user registration and authentication. The main function registers two users with their usernames and passwords. Then, authentication attempts are performed with correct and incorrect passwords for the registered users.

  1. Product Inventory Management:

Code:

Output:

Explanation: In the above example, a HashMap is used to manage a product inventory. The InventoryManager class manages the addition, removal, and printing of the product in the inventory. In the main function, three products are added to the inventory, and the resulting inventory is printed, and after removing one product the updated inventory is printed again.

Conclusion

  • A HashMap in Kotlin is a specialized type of collection that is designed to store data in the form of key-value pairs. This structure is particularly useful when you want to associate specific values (the values of the map) with unique identifiers (the keys of the map).
  • The HashMap includes a variety of methods that allow you to interact and manipulate the map. For example, you can add a new entry to the map using the put method, which takes a key and a value as parameters.
  • Its key differentiators from other structures lie in its use of unique keys for access, absence of a specific order, and performance characteristics in terms of quick key-based access compared to linear structures like arrays or lists, while differing from sorted structures like TreeMap by not maintaining any inherent order.
  • However, like other data structures, it has limitations and lacks thread safety, necessitating caution in concurrent environments. Therefore, it must be used carefully to ensure efficiency and safety, particularly in multi-threaded environments.