HashMap in Java

What is HashMap

A HashMap is a simple yet powerful way to store and get data.
HashMap is based on HashTable implementation, that implements the Map interface and stores items as key/value pairs.
HashMap permits only unique keys. It also permits only one null key (whereas HashTable does not allow any null key) but may have more than one null values.
It does not make garuntee of the order of the elements stored in it. For garuntee of the order please look at LinkedHashMap
All operations happen in HashMap are unsynchronized whereas, in HashTable all operations are synchronized.
Here is the internal working principle of HashMap

Performance

HashMap provides constant time performance i.e., O(1), for two basic operations get and put provided hash function disperses elements properly among the buckets.

Two parameters that affect the performance of the HashMap instance: capacity and load factor.

The capacity is the number of buckets in the hash table, and the initial capacity is simply the capacity at the time the hash table is created.

The load factor is a measure of how full the hash table is allowed to get before its capacity is automatically increased. When the number of entries in the hash table exceeds the product of the load factor and the current capacity, the hash table is rehashed, i.e., internal data structures are rebuilt, so that the hash table has approximately twice the number of buckets.

Iteration over HashMap requires time propertional to the capacity (the number of buckets) of the HashMap plus its size (the number of key/value pair mappings). Therefore, it is highly recommended not to set the initial capacity too high (or load factor too low) if iteration performance is important.

The expected number of entries in the map and its load factor should be taken into account when setting its initial capacity, so as to minimize the number of rehash operations.

As a general thumb of rule, the default load factor (.75) offers a good tradeoff between time and space costs.
Accessing in multi-threaded environment

Note that the HashMap implementation is not synchronized. So multiple threads access a hash map concurrently, and at least one of the threads modifies the map structurally, it must be synchronized externally. This is typically accomplished by synchronizing on some object that naturally encapsulates the map. If no such object exists, the map should be “wrapped” using the Collections.synchronizedMap method. This is best done at creation time, to prevent accidental unsynchronized access to the map:

Map m = Collections.synchronizedMap(new HashMap(...));

For multi-threaded environment you can use ConcurrentHashMap instead of Synchronized HashMap but if you have same number of reader and writer threads then ConcurrentHashMap and Synchronized HashMap will give the same performance. Therefore ConcurrentHashMap will give you best performance when you have many reader threads and very few writer threads.

More information could be found at https://docs.oracle.com/javase/8/docs/api/java/util/HashMap.html
HashMap Fail-fast

If the map is structurally modified at any time after the iterator is created, in any way except through the iterator’s own remove method, the iterator will throw a ConcurrentModificationException.  Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.

The fail-fast behavior of an iterator cannot be guaranteed and iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.

Set keys = hashMap.keySet();
for (Object key : keys) {
    hashMap.put(someObject, someValue); //it will throw the ConcurrentModificationException here
}

or

Set keys = hashMap.keySet();
for (Object key : keys) {
    hashMap.remove(key); //it will throw the ConcurrentModificationException here
}

Example

package com.roytuts.collections;
import java.util.HashMap;
import java.util.Map;
public class HashMapExample {
    public static void main(String[] args) {
        Map<String, String> cMap = new HashMap<>();
        cMap.put("RedHat", "Unix");
        cMap.put("Google", "Android");
        cMap.put("Apple", "iOS");
        cMap.put("Microsoft", "Windows");
        // iterate over HashMap
        cMap.forEach((k, v) -> System.out.println(k + " => " + v));
    }
}

Output

RedHat => Unix
Google => Android
Apple => iOS
Microsoft => Windows

Thanks for reading.

Leave a Reply

Your email address will not be published. Required fields are marked *