Showing posts with label HashMap. Show all posts
Showing posts with label HashMap. Show all posts

Difference between Hashtable, HashMap, TreeMap and LinkedHashMap

 
Map is one of the most important data structures and when we talk about Map all these 4 implementation classes (Hashtable, HashMap, TreeMap and LinkedHashMap) are most used. Hashtable, HashMap and LinkedHashMap are directly implements Map interface, but TreeMap implements Map interface through implementing SortedMap. Below are the few differences between these classes
Difference between Hashtable, HashMap, TreeMap and LinkedHashMap
  • HashMap implemented as same as Hashtable except it is unsynchronized and permits null. As common both HashMap and Hashtable won't have any ordering on keys or values.
  • TreeMap implemented based on red-black tree structure and it follows natural ordering on key. 
  • LinkedHashMap is a subclass of HashMap and inherits all properties of HashMap class and additionally its ordering will based on insertion order.
NOTE:
  • If we use any Map implementation classes and if the key is user-defined class Object then we need to override hashcode() and equals() methods. 
  • Next when we use TreeMap, by default they are sorted by keys. If we use user-defined class Object for key, then to compare with each other we need to implement Comparable interface.

Next lets see simple examples for each classes. 

Hashtable:


import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;

public class MapTest {

 public static void main(String[] args) {

  Map<String, String> map = new Hashtable<String, String>();
  map.put("1", "one");
  map.put("2", "two");
  map.put("3", "three");
  map.put("4", "four");
  map.put("5", "five");

  Iterator<?> itr = map.entrySet().iterator();
  while (itr.hasNext()) {
   Map.Entry myMap = (Map.Entry) itr.next();
   System.out.println(myMap.getKey() + " : " + myMap.getValue());
  }
 }
}

OUTPUT:


5 : five
4 : four
3 : three
2 : two
1 : one


HashMap:


import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class MapTest {

 public static void main(String[] args) {

  Map<String, String> map = new HashMap<String, String>();
  map.put("1", "one");
  map.put("2", "two");
  map.put("3", "three");
  map.put("4", "four");
  map.put("5", "five");

  Iterator<?> itr = map.entrySet().iterator();
  while (itr.hasNext()) {
   Map.Entry myMap = (Map.Entry) itr.next();
   System.out.println(myMap.getKey() + " : " + myMap.getValue());
  }
 }
}

OUPTUT:


3 : three
2 : two
1 : one
5 : five
4 : four


TreeMap:


import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;

public class MapTest {

 public static void main(String[] args) {

  Map<String, String> map = new TreeMap<String, String>();
  map.put("2", "two");
  map.put("3", "three");
  map.put("1", "one");
  map.put("4", "four");
  map.put("5", "five");

  Iterator<?> itr = map.entrySet().iterator();
  while (itr.hasNext()) {
   Map.Entry myMap = (Map.Entry) itr.next();
   System.out.println(myMap.getKey() + " : " + myMap.getValue());
  }
 }
}

OUTPUT:


1 : one
2 : two
3 : three
4 : four
5 : five


LinkedHashMap:


import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;

public class MapTest {

 public static void main(String[] args) {

  Map<String, String> map = new LinkedHashMap<String, String>();
  map.put("2", "two");
  map.put("3", "three");
  map.put("1", "one");
  map.put("4", "four");
  map.put("5", "five");

  Iterator<?> itr = map.entrySet().iterator();
  while (itr.hasNext()) {
   Map.Entry myMap = (Map.Entry) itr.next();
   System.out.println(myMap.getKey() + " : " + myMap.getValue());
  }
 }
}

OUTPUT:


2 : two
3 : three
1 : one
4 : four
5 : five

Case Insensitive HashMap

 
Array with Even and Odd numbers

This is one of the programming interview questions which asked in recent interview. Need to implement HashMap which will take case insensitive keys. Here we should not confuse with case sensitive, since HashMap by default will hold keys with case sensitive. But as an alternate we need to implement HashMap with Case Insensitive. 
For example: We need to store "abc" and "ABc" in key. Default HashMap will have 2 entries since its case sensitive, where as we need to store only 1 key and value with "abc" with case insensitive. 

So how we can define HashMap with case insensitive? 

We can implement in various ways like implementing Map interface or extending HashMap class etc., In below example we will see about implementing Case Insensitive HashMap by extending HashMap class.


import java.util.HashMap;
import java.util.Map;

public class HashMapCaseInsensitive extends HashMap<String, String>{
 
 @Override
 public String put(String key, String value) {
  return super.put(key.toLowerCase(), value);
 }

 @Override
 public String get(Object key) {
  return super.get(key.toString().toLowerCase());
 }
 
 public static void main(String[] args) {
  
  Map<String, String> hm = new HashMapCaseInsensitive();
  
  hm.put("abc", "one");
  hm.put("ABc", "two");
  hm.put("aBc", "three");
  
  System.out.println("HASHMAP SIZE  : "+hm.size());
  
  System.out.println("GET ABC VALUE : "+hm.get("ABC"));
 }
}


OUTPUT:


HASHMAP SIZE  : 1
GET ABC VALUE : three









Difference between HashMap and HashTable in Java


Map is one of the important Interface in Java Collections and Maps contains key and value which always stores unique keys and values. Both HashMap and Hashtable implements Map interface and works based on hashing algorithm. 

Even HashMap and Hashtable implements Map interface but there are few important difference between these. Before using HashMap and Hashtable in application we need to know the functionality of both, by mistake if we select incorrect implementation class then it leads to lot of performance impact and error in our application. 

From JDK 1.4 onwards Hashtable included in Collection
Lets see few important difference between HashMap and Hashtable in Java.


Difference between HashMap and Hashtable.

  • First important difference between HashMap and Hashtable is, Hashtable is thread-safe (by default synchronized) and HashMap is not thread-safe.
  • HashMap allows null key and null value, but Hashmap won't allow null key and value which will give runtime NullPointerException.
  • As performance wise HashMap will be faster than Hashtable since its not synchronized. 
  • Iterator in HashMap class is a fail-fast iterator and enumerator in Hashtable is fail-safe and throw ConcurrentModificationException if any other Thread modifies.


Alternate for Hashtable:

If we need to use HashMap with thread-safe then we can convert HashMap to synchronized HashMap or we can for ConcurrentHashMap class. How to convert HashMap to synchronized HashMap have seen in our earlier tutorial.

Below are simple example for HashMap and Hashtable.

HashMap:


public  class MyTestClass {

 public static void main(String[] args) {
  
  Map<String, String> hm = new HashMap<String, String>();
  hm.put(null, null);
  hm.put("1", "one");
  System.out.println("Value : "+ hm.get(null));
  
  // Converting HashMap to Synchronized HashMap
  hm = Collections.synchronizedMap(hm);  
 }
}


Hashtable:


public  class MyTestClass {

 public static void main(String[] args) {
  
  Map<String, String> ht = new Hashtable<String, String>();
  
  // gives NullPointerException
  //ht.put(null, null);
  
  ht.put("1", "one");
  System.out.println("Value : "+ ht.get(null));
 }
}









How to convert HashMap to Synchronized Map ?

In this tutorial we will see about how to convert HashMap to synchronized Map. As we know already that HashMap is not synchronized by default.

Synchronize is nothing but making the HashMap to thread safe and by multi-threading environment only one user can remove or edit the Map values. For example if we are using HashMap only for read operation then making synchronized Map is not necessary. Only when multi users or more threads tries to update or remove same key or value from HashMap then we need to make HashMap synchronized for thread safe purpose.

In Java we can do this very easily by using java.util.Collections class as like give below.



Map<String, Object> myMap = new HashMap<String, Object>();
.
.
.  
.
myMap = Collections.synchronizedMap(myMap);


From above code snippet we have declared myMap as HashMap and later in below code we have converted same HashMap instance to synchronized Map. Since this is a simple interview question which asked in 2 to 3 yrs experience level. Hope you are clear now how to convert HashMap to synchronized Map.

Above we have seen how to convert HashMap to SynchronizedMap. Even by converting SynchronizedMap its not guarantee that values will be thread safe we are editing or removing on same Object using multiple Thread. As per  Collections#synchronizedMap() in Oracle docs we need to make operations on Map with synchronized block as mentioned in Oracle docs.  

Lets see all scenarios with details example of 

  1. Accessing updated HashMap without converting to SynchronizedMap under Multi Threading.
  2. Accessing updated HashMap just converting to SynchronizedMap under Multi Threading.
  3. Accessing updated HashMap with converted to SynchronizedMap & Synchronized block under Multi Threading.

Example - 1 : Accessing updated HashMap without converting to SynchronizedMap under Multi Threading.


public class HashMapTest implements Runnable{
 
 // Initializing new HashMap
 private Map<String, String> myMap = new HashMap<String, String>();
 
 public void run() {
  String threadName = Thread.currentThread().getName();
  String oldValue = myMap.get("myKey");
  String newValue = oldValue+threadName;
  myMap.put("myKey", newValue);
  System.out.println(threadName+" : "+myMap.get("myKey"));
 }
 
 public static void main(String[] args) {
  HashMapTest obj = new HashMapTest();
  
  // Adding values into HashMap
  obj.addValues();
  
  // Creating multiple Thread and starting
  for(int i=0;i<5;i++){
   new Thread(obj).start();
  }
  
 }
 public void addValues(){
  myMap.put("myKey", "Java Discover - ");
 }
}


OUTPUT:


Thread-0 : Java Discover - Thread-3
Thread-1 : Java Discover - Thread-3
Thread-2 : Java Discover - Thread-3
Thread-3 : Java Discover - Thread-3
Thread-4 : Java Discover - Thread-3




In above example we have placed 1 value in HashMap and in run() method we trying to upend Thread name to existing value. Each thread names need to be upended in the value, where as we can see only Thread-3 has upended with original value. Remaining 4 Thread names are not updated correctly. Next example lets see just by converting HashMap to SynchronizedMap.



Example - 2 : Accessing updated HashMap just converting to SynchronizedMap under Multi Threading.


public class HashMapTest implements Runnable{
 
 // Initializing new HashMap
 private Map<String, String> myMap = new HashMap<String, String>();
 
 public void run() {
  String threadName = Thread.currentThread().getName();
  String oldValue = myMap.get("myKey");
  String newValue = oldValue+threadName;
  myMap.put("myKey", newValue);
  System.out.println(threadName+" : "+myMap.get("myKey"));
 }
 
 public static void main(String[] args) {
  HashMapTest obj = new HashMapTest();
  
  // Adding values into HashMap
  obj.addValues();
  
  // Converting HashMap to Synchronized Map 
  obj.convertMapToSynMap();
  
  // Creating multiple Thread and starting
  for(int i=0;i<5;i++){
   new Thread(obj).start();
  }
  
 }
 public void convertMapToSynMap(){
  myMap = Collections.synchronizedMap(myMap);
 }
 public void addValues(){
  myMap.put("myKey", "Java Discover - ");
 }
}


OUTPUT:


Thread-0 : Java Discover - Thread-1
Thread-1 : Java Discover - Thread-1
Thread-2 : Java Discover - Thread-1Thread-2
Thread-3 : Java Discover - Thread-1Thread-2Thread-3
Thread-4 : Java Discover - Thread-1Thread-2Thread-3Thread-4



Even by making SynchronizedMap we are getting wrong output when mutiple thread trying to update same Map key value. In above code we can see Thread-0 is missing. Next lets see how to thread safe when we edit under multi threading on same object. 

Example - 3 : Accessing updated HashMap with converted to SynchronizedMap & Synchronized block under Multi Threading.


public class HashMapTest implements Runnable{
 
 // Initializing new HashMap
 private Map<String, String> myMap = new HashMap<String, String>();
 
 public void run() {
  String threadName = Thread.currentThread().getName();
  // Synchronized block 
  synchronized (myMap) {
   String oldValue = myMap.get("myKey");
   String newValue = oldValue+threadName;
   myMap.put("myKey", newValue);
  }  
  System.out.println(threadName+" : "+myMap.get("myKey"));
 }
 
 public static void main(String[] args) {
  HashMapTest obj = new HashMapTest();
  
  // Adding values into HashMap
  obj.addValues();
  
  // Converting HashMap to Synchronized Map 
  obj.convertMapToSynMap();
  
  // Creating multiple Thread and starting
  for(int i=0;i<5;i++){
   new Thread(obj).start();
  }
  
 }
 public void convertMapToSynMap(){
  myMap = Collections.synchronizedMap(myMap);
 }
 public void addValues(){
  myMap.put("myKey", "Java Discover - ");
 }
}

OUTPUT:


Thread-0 : Java Discover - Thread-0Thread-1
Thread-1 : Java Discover - Thread-0Thread-1
Thread-2 : Java Discover - Thread-0Thread-1Thread-2Thread-3
Thread-3 : Java Discover - Thread-0Thread-1Thread-2Thread-3
Thread-4 : Java Discover - Thread-0Thread-1Thread-2Thread-3Thread-4

Now we see all Thread names are upended correctly from 0 to 5. Order doesn't matter since Thread will called according priority. 









Using keySet(), entrySet() and values() methods in HashMap

Today we will see about using keySet(), value() and entrySet() methods in HashMap. Basically all these methods will be used to get the list of keys and values from HashMap. Lets see each one separately how its used in Java.
  • keySet() method is used to get only the list of keys in HashMap.
  • value() method is used to get only the list of values in HashMap.
  • entrySet() method is used to get both key and values from the HashMap.

Below is a simple example program which will explain about using all these 3 methods.

 


public class HashMapTest {
 
 public static void main(String[] args) {
 
    Map<String, String> hm = new HashMap<String, String>();
    hm.put("key1", "Bangalore");
    hm.put("key3", "India");
    hm.put("key2", "Mumbai");
    hm.put("key5", "New Delhi");
    hm.put("key4", "Chennai");
    
    new HashMapTest().getOnlyKeyList(hm);
    new HashMapTest().getOnlyValueList(hm);
    new HashMapTest().getBothKeyValue(hm);    
 }
 
 // Fetching only Keys by using keySet() method
 public void getOnlyKeyList(Map<String, String> hm){
  Iterator<String> itr = ((Set<String>) hm.keySet()).iterator();
  System.out.println("USING keyset() :::::::::::: ");
  while(itr.hasNext()){
   String key = itr.next();
   System.out.println("KEY : "+key);
  }
 }
 
 // Fetching only values by using value() method
 public void getOnlyValueList(Map<String, String> hm){
  Iterator<String> itr = hm.values().iterator();
  System.out.println("\n\nUSING value() :::::::::::: ");
  while(itr.hasNext()){
   String value = itr.next();
   System.out.println("VALUE : "+value);
  }
 }
 
 // Fetching both keys and values using entrySet() method
 public void getBothKeyValue(Map<String, String> hm){
  Iterator <Map.Entry<String,String>>entryset = hm.entrySet().iterator();
  System.out.println("\n\nUSING entryset() :::::::::::: ");
  while(entryset.hasNext()){
   Map.Entry <String,String>entry=entryset.next();
   String key = entry.getKey();
   String value = entry.getValue();
   System.out.println("KEY : "+key +" - VALUE : "+value);
  }
 }
}



OUTPUT:



USING keyset() :::::::::::: 
KEY : key1
KEY : key3
KEY : key5
KEY : key2
KEY : key4


USING value() :::::::::::: 
VALUE : Bangalore
VALUE : India
VALUE : New Delhi
VALUE : Mumbai
VALUE : Chennai


USING entryset() :::::::::::: 
KEY : key1 - VALUE : Bangalore
KEY : key3 - VALUE : India
KEY : key5 - VALUE : New Delhi
KEY : key2 - VALUE : Mumbai
KEY : key4 - VALUE : Chennai