Contents of page :
Employee object overrides:
>equals method - helps in checking equality of employee objects used as key in entry objects.
>hashCode method - helps in finding bucket’s index on which data will be stored. 
| 
       @Override 
    public boolean equals(Object o){ 
           if(o==null) 
                  return false; 
           if(this.getClass()!=o.getClass()) 
                  return false; 
           Employee e=(Employee)o; 
           return e.id.equals(this.id) && e.name.equals(this.name);           
    } 
    @Override 
    public int hashCode(){ 
           return id.hashCode() + name.hashCode();       
    } | 
| 
package com.ankit; 
/** 
* @author AnkitMittal 
* Copyright (c), AnkitMittal . All Contents are copyrighted and must not be reproduced in any form. 
* This class provides custom implementation of LinkedHashSet(without using java api's- we will be using HashMapCustom)- which allows does not allow you to store duplicate values. 
* Note- implementation does not allow you to store null values. 
* maintains insertion order. 
* @param <K> 
* @param <V> 
*/ 
class LinkedHashSetCustom<E>{ 
    private LinkedHashMapCustom<E, Object> linkedHashMapCustom; 
    public LinkedHashSetCustom(){ 
           linkedHashMapCustom=new LinkedHashMapCustom<>(); 
    } 
    /** 
     * add objects in LinkedHashSetCustom. 
     */ 
    public void add(E value){ 
           linkedHashMapCustom.put(value, null); 
    } 
    /** 
     * Method returns true if LinkedHashSetCustom contains the object. 
     * @param key 
     */ 
    public boolean contains(E obj){ 
           return linkedHashMapCustom.contains(obj) !=null ? true :false; 
    } 
    /** 
     * Method displays all objects in LinkedHashSetCustom. 
     * insertion order is not guaranteed, for maintaining insertion order refer LinkedHashSet. 
     */ 
    public void display(){ 
       linkedHashMapCustom.displaySet(); 
    } 
    /** 
     * Method removes object from setCustom. 
     * insertion order is not guaranteed, for maintaining insertion order refer LinkedHashSet. 
     * @param obj 
     */ 
    public boolean remove(E obj){ 
       return linkedHashMapCustom.remove(obj); 
    }  
} 
/** 
* @author AnkitMittal 
* Copyright (c), AnkitMittal . All Contents are copyrighted and must not be reproduced in any form. 
* Employee class- to be used as key in HashSetCustom. 
*/ 
class Employee { 
    private String id; 
    private String name; 
    /** 
     * Employee constructor 
     */ 
    public Employee(String id, String name) { // constructor 
           this.id = id; 
           this.name = name; 
    } 
    @Override 
    public String toString() { 
           return "Employee[id=" + id + ", name=" + name + "] "; 
    } 
    @Override 
    public boolean equals(Object o){ 
           if(o==null) 
                  return false; 
           if(this.getClass()!=o.getClass()) 
                  return false; 
           Employee e=(Employee)o; 
           return e.id.equals(this.id) && e.name.equals(this.name);           
    } 
    @Override 
    public int hashCode(){ 
           return id.hashCode() + name.hashCode();       
    } 
} 
/** Copyright (c), AnkitMittal  JavaMadeSoEasy.com */ 
 /** 
 * @author AnkitMittal 
 * Copyright (c), AnkitMittal . All Contents are copyrighted and must not be reproduced in any form. 
 * This class provides custom implementation of LinkedHashMap(without using java api's)- which allows us to store data in key-value pair form. 
 * It maintains insertion order, uses DoublyLinkedList for doing so. 
 * If key which already exists is added again, its value is overridden but insertion order does not change, 
 * BUT, if key-value pair is removed and value is again added than insertion order changes(which is quite natural behaviour). 
 * @param <K> 
 * @param <V> 
 */ 
class LinkedHashMapCustom<K, V> { 
     private Entry<K,V>[] table;   //Array of Entry. 
     private int capacity= 4;  //Initial capacity of HashMap 
     private Entry<K,V> header; //head of the doubly linked list. 
     private Entry<K,V> last; //last of the doubly linked list. 
     /* 
      * before and after are used for maintaining insertion order. 
      */ 
     static class Entry<K, V> { 
         K key; 
         V value; 
         Entry<K,V> next; 
         Entry<K,V> before; 
            Entry<K,V> after; 
         public Entry(K key, V value, Entry<K,V> next){ 
             this.key = key; 
             this.value = value; 
             this.next = next; 
         } 
     } 
    @SuppressWarnings("unchecked") 
    public LinkedHashMapCustom(){ 
       table = new Entry[capacity]; 
    } 
    /** 
     * Method allows you put key-value pair in LinkedHashMapCustom. 
     * If the map already contains a mapping for the key, the old value is replaced. 
     * Note: method does not allows you to put null key thought it allows null values. 
     * Implementation allows you to put custom objects as a key as well. 
     * Key Features: implementation provides you with following features:- 
     *     >provide complete functionality how to override equals method. 
     *  >provide complete functionality how to override hashCode method. 
     * @param newKey 
     * @param data 
     */ 
    public void put(K newKey, V data){ 
       if(newKey==null) 
           return;    //does not allow to store null. 
       int hash=hash(newKey); 
       Entry<K,V> newEntry = new Entry<K,V>(newKey, data, null); 
       maintainOrderAfterInsert(newEntry);        
        if(table[hash] == null){ 
         table[hash] = newEntry; 
        }else{ 
           Entry<K,V> previous = null; 
           Entry<K,V> current = table[hash]; 
           while(current != null){ //we have reached last entry of bucket. 
           if(current.key.equals(newKey)){                   
               if(previous==null){  //node has to be insert on first of bucket. 
                     newEntry.next=current.next; 
                     table[hash]=newEntry; 
                     return; 
               } 
               else{ 
                   newEntry.next=current.next; 
                   previous.next=newEntry; 
                   return; 
               } 
           } 
           previous=current; 
             current = current.next; 
         } 
         previous.next = newEntry; 
        } 
    } 
    /** 
     * below method helps us in ensuring insertion order of LinkedHashMapCustom after new key-value pair is added. 
     */ 
    private void maintainOrderAfterInsert(Entry<K, V> newEntry) { 
       if(header==null){ 
           header=newEntry; 
           last=newEntry; 
           return; 
       } 
       if(header.key.equals(newEntry.key)){ 
           deleteFirst(); 
           insertFirst(newEntry); 
           return; 
       } 
       if(last.key.equals(newEntry.key)){ 
           deleteLast(); 
           insertLast(newEntry); 
           return; 
       } 
       Entry<K, V> beforeDeleteEntry=    deleteSpecificEntry(newEntry); 
       if(beforeDeleteEntry==null){ 
           insertLast(newEntry); 
       } 
       else{ 
           insertAfter(beforeDeleteEntry,newEntry); 
       } 
    } 
    /** 
     * below method helps us in ensuring insertion order of LinkedHashMapCustom, after deletion of key-value pair. 
     */ 
    private void maintainOrderAfterDeletion(Entry<K, V> deleteEntry) { 
       if(header.key.equals(deleteEntry.key)){ 
           deleteFirst(); 
           return; 
       } 
       if(last.key.equals(deleteEntry.key)){ 
           deleteLast(); 
           return; 
       } 
       deleteSpecificEntry(deleteEntry); 
    } 
    /** 
     * returns entry after which new entry must be added. 
     */ 
    private void insertAfter(Entry<K, V> beforeDeleteEntry, Entry<K, V> newEntry) { 
       Entry<K, V> current=header; 
           while(current!=beforeDeleteEntry){ 
                  current=current.after;  //move to next node. 
           } 
           newEntry.after=beforeDeleteEntry.after; 
           beforeDeleteEntry.after.before=newEntry; 
           newEntry.before=beforeDeleteEntry; 
           beforeDeleteEntry.after=newEntry; 
    } 
    /** 
     * deletes entry from first. 
     */ 
    void deleteFirst(){ 
       if(header==last){ //only one entry found. 
                  header=last=null; 
                  return; 
           } 
           header=header.after; 
           header.before=null; 
    } 
    /** 
     * inserts entry at first. 
     */ 
    void insertFirst(Entry<K, V> newEntry){       
           if(header==null){ //no entry found 
                  header=newEntry; 
                  last=newEntry; 
                  return; 
           } 
           newEntry.after=header; 
           header.before=newEntry; 
           header=newEntry; 
    } 
    /** 
     * inserts entry at last. 
     */ 
    void insertLast(Entry<K, V> newEntry){ 
           if(header==null){ 
                  header=newEntry; 
                  last=newEntry; 
                  return; 
           } 
           last.after=newEntry; 
           newEntry.before=last; 
           last=newEntry; 
    } 
    /** 
     * deletes entry from last. 
     */ 
    void deleteLast(){ 
           if(header==last){ 
                  header=last=null; 
                  return; 
           } 
           last=last.before; 
           last.after=null; 
    } 
    /** 
     * deletes specific entry and returns before entry. 
     */ 
    private Entry<K, V> deleteSpecificEntry(Entry<K, V> newEntry){ 
           Entry<K, V> current=header; 
           while(!current.key.equals(newEntry.key)){ 
                  if(current.after==null){   //entry not found 
                        return null; 
                  } 
                  current=current.after;  //move to next node. 
           } 
           Entry<K, V> beforeDeleteEntry=current.before; 
           current.before.after=current.after; 
           current.after.before=current.before;  //entry deleted 
           return beforeDeleteEntry; 
    } 
    /** 
     * Method returns value corresponding to key. 
     * @param key 
     */ 
    public V get(K key){ 
        int hash = hash(key); 
        if(table[hash] == null){ 
         return null; 
        }else{ 
         Entry<K,V> temp = table[hash]; 
         while(temp!= null){ 
             if(temp.key.equals(key)) 
                 return temp.value; 
             temp = temp.next; //return value corresponding to key. 
         }          
         return null;   //returns null if key is not found. 
        } 
    } 
    /** 
     * Method removes key-value pair from HashMapCustom. 
     * @param key 
     */ 
    public boolean remove(K deleteKey){ 
       int hash=hash(deleteKey); 
      if(table[hash] == null){ 
            return false; 
      }else{ 
        Entry<K,V> previous = null; 
        Entry<K,V> current = table[hash]; 
        while(current != null){ //we have reached last entry node of bucket. 
           if(current.key.equals(deleteKey)){ 
               maintainOrderAfterDeletion(current); 
               if(previous==null){  //delete first entry node. 
                      table[hash]=table[hash].next; 
                     return true; 
               } 
               else{ 
                     previous.next=current.next; 
                   return true; 
               } 
           } 
           previous=current; 
             current = current.next; 
          } 
        return false; 
      } 
    } 
    /** 
     * Method displays all key-value pairs present in HashMapCustom., 
     * insertion order is not guaranteed, for maintaining insertion order refer linkedHashMapCustom. 
     * @param key 
     */ 
    public void display(){ 
       Entry<K, V> currentEntry=header; 
       while(currentEntry!=null){ 
           System.out.print("{"+currentEntry.key+"="+currentEntry.value+"}" +" "); 
           currentEntry=currentEntry.after; 
       } 
    } 
    /** 
     * Method implements hashing functionality, which helps in finding the appropriate bucket location to store our data. 
     * This is very important method, as performance of HashMapCustom is very much dependent on  this method's implementation. 
     * @param key 
     */ 
    private int hash(K key){ 
        return Math.abs(key.hashCode()) % capacity; 
    } 
    /** 
     * Method returns null if LinkedHashSetCustom does not contain object. 
     * @param key 
     */ 
    public K contains(K key){ 
        int hash = hash(key); 
        if(table[hash] == null){ 
         return null; 
        }else{ 
         Entry<K,V> temp = table[hash]; 
         while(temp!= null){ 
             if(temp.key.equals(key)) 
                 return key; 
             temp = temp.next; //return value corresponding to key. 
         }          
         return null;   //returns null if key is not found. 
        } 
    } 
    /** 
     * Method displays all objects in LinkedHashSetCustom. 
     * insertion order is maintained. 
     * @param key 
     */ 
    public void displaySet(){ 
       Entry<K, V> currentEntry=header; 
       while(currentEntry!=null){ 
           System.out.print(currentEntry.key+" "); 
           currentEntry=currentEntry.after; 
       } 
    } 
} 
 /** Copyright (c), AnkitMittal  JavaMadeSoEasy.com */ 
/** 
 * Main class- to test HashMap functionality. 
 */ 
public class LinkedHashSetCustomEmp { 
    public static void main(String[] args) { 
       LinkedHashSetCustom<Employee> linkedHashSetCustom = new LinkedHashSetCustom<Employee>(); 
       linkedHashSetCustom.add(new Employee("10", "sam")); 
       linkedHashSetCustom.add(new Employee("21", "amy")); 
       linkedHashSetCustom.add(new Employee("31", "rob")); 
       linkedHashSetCustom.add(new Employee("41", "sam")); 
       linkedHashSetCustom.add(new Employee("42", "wil")); 
       System.out.println("LinkedHashSetCustom contains employee with id=21 & name='amy' : "+linkedHashSetCustom.contains(new Employee("21", "amy"))); 
           System.out.println("LinkedHashSetCustom contains employee with id=51 & name='pat' : "+linkedHashSetCustom.contains(new Employee("51", "pat"))); 
        System.out.print("Displaying : "); 
        linkedHashSetCustom.display(); 
        System.out.println("\n\nemployee with id=21 & name='amy' removed: "+linkedHashSetCustom.remove(new Employee("21", "amy"))); 
        System.out.println("employee with id=51 & name='pat' removed: "+linkedHashSetCustom.remove(new Employee("51", "pat"))); 
        System.out.print("Displaying : "); 
        linkedHashSetCustom.display(); 
    } 
} 
/*Output 
LinkedHashSetCustom contains employee with id=21 & name='amy' : true 
LinkedHashSetCustom contains employee with id=51 & name='pat' : false 
Displaying : Employee[id=10, name=sam]  Employee[id=21, name=amy]  Employee[id=31, name=rob]  Employee[id=41, name=sam]  Employee[id=42, name=wil]  
employee with id=21 & name='amy' removed: true 
employee with id=51 & name='pat' removed: false 
Displaying : Employee[id=10, name=sam]  Employee[id=31, name=rob]  Employee[id=41, name=sam]  Employee[id=42, name=wil]  
*/ | 
Having any doubt? or you you liked the tutorial! Please comment in below section.
Please express your love by liking JavaMadeSoEasy.com (JMSE) on facebook, following on google+ or Twitter.
RELATED LINKS>