Java Hashmap tutorial

Java HashMap is a HashTable based implementation of Map. This is the reason why the interviewer always asks for the difference between HashMap and HashTable. HashMap is mostly equated to HashTable except below two differences.

  1. HashMap is unsynchronized while HashTable is synchronized.
  2. HashMap permits null while HashTable doesn’t.

Important Property of HashMap

DEFAULT_INITIAL_CAPACITY Default Initial Capacity(2 power n). A number of elements HashMap can contain.
MAXIMUM_CAPACITY Maximum Capacity of HashMap (2 power n).
LOAD FACTOR Defines the threshold of HashMap. When re-sizing will occur in HashMap.
DEFAULT_LOAD_FACTOR   Will be used when no load factor is defined in the constructor of HashMap.
SIZE
 The number of key-value pair mapping, HashMap contains.

Creation of HashMap

When there is no parameter defined while creating HashMap default Initial Capacity(16) and Default load factor(0.75) will be used. This HashMap can contain up to 16 elements and resize of HashMap will occur when the 13th element will be inserted. This is because the load factor is 75%(.75) and this threshold will be crossed when you add the 13th element(12+1).

You can also provide initial capacity and loadFactor. But initial capacity cannot be more than maximum capacity (2 power 30) and load factor cannot be zero or negative number.

Addition of element in HashMap

In order to add an element, you need to provide 2 things, key, and value.

Key: key with which specified value will be associated. null is allowed.

Value: value to be associated with a specified key.

First HashMap will generate a hashcode for the given key and then check if there is any value already associated with the given key or not. If yes then it will return the already associated value. Else it will add value in HashMap with the provided key.

Bullet Point

  1. HashMap doesn’t give any Guarantee in order of elements in Map(Means Order can change over time).
  2. HashMap provides Constant time performance for get & set operation(If the proper Hashing algorithm is used).
  3. Time requires to Iterate collection is proportional to “Capacity“(Elements it can hold) & Size(Elements it is holding currently) of HashMap.
  4. In the case of iteration, performance is more important then it is advisable to not set the initial capacity too high and load factor too low. As performance is directly proportional to Initial Capacity and load Factor.
    • capacity is the number of buckets in the hash table.
    • initial capacity(Default Value is 16) is simply the capacity at the time the hash table is created.
    • The load factor(Default value .75) 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 (that is, internal data structures are rebuilt).
  5. Use “Collections.synchronizedMap()” method to make Map synchronised.
  6. Iterators returned by HashMap class is “fail-fast“.
  7. HashMap is backed by an Array(Key) and LinkedList(Value).
  8. HashMap uses hashcode(Using Key) to identify the exact location where an object should be placed or retrieved in HashMap.
  9. In the end, HashCode returns the exact location(Index) in the backing array.
  10. Backed Array has a fixed size. So whenever Array is full(Number of keys in this map reaches its threshold). A new Array with a new capacity will be created and all elements will be added to this new Array.
  11. HashCode will be used in both cases(Adding and Retrieving Object) while the equals() method may or may not be used in any case.
  12. The best candidate for Key in HashMap would be an Immutable Class with properly implement Equals and Hashcode method(Example: String Class).
  13. The better hashcode and equals method implementation is the better performance of HashMap would be.
  14. In such a way, String and Wrapper classes of all Primitives will be great candidates for keys in HashMap.

What is ReHashing

Every HashMap has a predefined size (Initial Capacity) and logic to increment this size(Load Factor) whenever required(When threshold limit crossed).

Example :

Create HashMap with below configuration

Initial Capacity = 16 (Default Initial Capacity)

Load Factor : .75 (Default load factor)

The moment you add the 13th element in the given HashMap, the Threshold limit is crossed for the given HashMap and the system will create a new backing keyset array(The size of this array will be double of the previous array). The system will have to again calculate the exact bucket where elements from the previous bucket should be placed and all elements from the old HashMap will be copied to the new HashMap. This whole process is called ReHashing because Hashcode is calculated for each element again.

Because over time HashMap might be reHashed and the order could get change.

Example of HashMap

Here in this example, you will learn below points

  1. How to iterate a Map
  2. Different ways of iterating a Map
  3. When HashCode and Equals will get called. (Pay close attention to the output of HashCode and equals method call)
import java.util.HashMap;
import java.util.Map;

public class HashMapExample {

  public static void main(String[] args) {

    Map<JBT, Integer> m1 = new HashMap<JBT, Integer>();

    JBT t1 = new JBT(1, 2);
    JBT t2 = new JBT(1, 3);
    JBT t3 = new JBT(2, 1);

    m1.put(t1, 1);
    m1.put(t2, 2);
    m1.put(t3, 3);
    System.out.println("Addition Done");

    /*
     * Below you can find 3 different ways to iterate a Map. Uncomment
     * different section and see the different in Output. Pay attention to
     * when Hashcode and Equals is called
     */

    /*		Set s = m1.entrySet();
    		for (Iterator i = s.iterator(); i.hasNext();) {
    			Map.Entry me = (Map.Entry) i.next();
    			System.out.println(me.getKey() + " : " + me.getValue());
    		}
    */
    /*		for (Map.Entry<JBT, Integer> entry : m1.entrySet()) {
    			System.out.println("Key : " + entry.getKey() + " Value : "
    					+ entry.getValue());
    		}
    */
    for (Object key : m1.keySet()) {
      System.out.println("Key : " + key.toString() + " Value : " + m1.get(key));
    }
  }
}

class JBT {
  int i, j;

  JBT(int i, int j) {
    this.i = i;
    this.j = j;
  }

  @Override
  public int hashCode() {
    System.out.println("Inside HashCode Method");
    int k = i + j;
    return k;
  }

  @Override
  public boolean equals(Object obj) {

    System.out.println("Inside Equals Method");
    if (i == ((JBT) obj).i && j == ((JBT) obj).j) return true;
    else return false;
  }

  @Override
  public String toString() {
    return String.valueOf(i).concat(String.valueOf(j));
  }
}

7 Comments

  1. Hey very good work.. its short and sweet to understand, please add bit more information about get and put method how hash map work internally, it will make complete of it then

    Thank you .

  2. Nice Post! Pls I stll dont understand these Points:

    1.HashMap is backed by an Array(Key) and LinkedList(Value).
    2.Iterators returned by HashMap class is “fail-fast“.

    3.When there is no parameter defined while creating HashMap default Initial Capacity(16) and Default load factor(0.75) will be used. This HashMap can contain up to 16 element and resizing of HashMap will occur when 13th element will be inserted. This is because load factor is 75%(.75) and this threshold will be crossed when you add 13th element(12+1).

  3. Thanks a ton Jayshri. It is a very good work. Collection was the topic I used to think it is such a vast topic and thought I will never beable to grasp it. But you have made it so so so easy. Million thanks to you. You have helped me a lot. God bless you.

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.