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>