What happens if we do not override hashcode() and equals() in hashmap?

What happens if we do not override hashcode() and equals() in hashmap?

In this post, let us understand what is the use of equals() and hashcode(), why it is important to override them and what will happen if we dont override them

To understand this post, it is expected to have knowledge of Internal Working of HashMap.

If not aware of internal working of hashmap, lets have a quick overview.

Important Points of HashMap:

  • HashMap has Key and Value pairs.
  • HashMap is not Synchronized (i.e. Not Thread Safe)
  • HashMap has no guarantees as to the order of the map
  • HashMap does not guarantee that the order will remain constant over time.
  • HashMap allows only one Null Key, Which will always be stored at 0th position in the bucket
  • HashMap can have multiple null values, but only one null key is allowed
  • HashMap can be Synchronized externally using Collections.synchronizedMap(HashMap)

Internal Working of HashMap: (Quick Summary)
So How does HashMap works Internally?
HashMap has the implementation of Map Interface.  HashMap has key and value pairs.

The initial capacity of HashMap is 16 and where as load factor is 0.75.

What is Initial Capacity and LoadFactor?
The initial capacity is the number of buckets in the hashtable and the load factor is a measure of how full the hash table is allowed to get before its capacity is automatically increased.

When we try to put a Key and Value within HashMap, first the equals method will check whether both objects are equal and then it hashes and find the bucket where to insert this Key and Value. If both the objects are equal, it will override the already existing Object in Bucket.
In Short,  equals() will help us to identify if the object is unique and HashCode helps us to identify the bucket in which the values has to be Stored.

Now Let us see this with an Example,

For the below Example, we are going to create Employee class and another Main class.

We have created an Employee class, Now let us create a main method

equals() and hashcode() – Not Overridden:

The above code, we haven’t implemented equals() and hashcode() method. Let us the what output our code gives,

Though both objects are equal() since we haven’t overridden the equals(), so it considers both the objects as unique keys. We also haven’t overridden the hashcode(), so even when both objects are same, their hashcode is different.

How it works without Overriding equals() and hashcode()?

From the output, first it compares two objects (eventhough they are equals, since we have not overridden the equals()) it shows both the objects are not equals and will be considered as Unqiue Keys and with values.

From the hashing, it goes to different buckets – duplicate entries for same object.

Override equals() and Not hashcode:

Now let us Override only Equals() method,

 

Now after overriding equals method, let use slightly modify our main method,

Now after overriding only equals() method, we can see both objects are compared and identified as equals objects (Both Objects are  Equal: true)

But here the problem is, though both the objects are equal() the hashcode() is different and so the both objects will be stored in different buckets.

If both objects are equal and if it points to same bucket then the value will be overridden.

Override hashcode() and Not equals():

When we run the code,

Since we have overridden only hashcode() and not equals method() –> The objects comparison becomes false, means the objects are unique. So even though the hashcode points to same bucket, the objects are considered as unique keys and both the values will be stored in the bucket.

override both equals() and hashcode():

Now let us run the above code and see,

Since we have overridden the equals() and hashcode(), when inserting in map — It has identified both objects are equal and both has same hashcode values. So when trying to insert into the bucket, only one value will be inserted that is the reason we have only one element in hashmap (Key is: Employee@13665 Value is: Two)

Complete Code:

 

How does hashmap work Internally | Internal Working of HashMap

How does hashmap work Internally – Explained:

In this post, let us see how hashmap works internally – How the elements are added and retrieved from buckets.

Features of HashMap:

  • Implementation of Map Interface – With Key and Value pairs
  • No order of maps, also order of map changes over time
  • Accepts one null key and multiple null values
  • Keys should be unique and cannot have duplicates
  • Unsynchronized i.e. Not Thread Safe
  • Initial capacity is 16 and load factor is 0.75
  • Synchronized externally using Collections.SynchronizedMap(hashmap)

What is Initial Capacity and Load factor?

Initial Capacity is number of buckets in hashtable, that i.e. by default HashMap provides 16 buckets when created, we can define number of buckets required when creating the HashMap.

Load Factor indicates when a certain capacity of elements are populated in HashMap, it size will increaase. Load factor decides how much of capacity should be filled before increasing the size of hashmap.

https://www.youtube.com/watch?v=nff4KWFtwW0&feature=youtu.be

HashMap Creation:

  • public HashMap()
  • public HashMap(int initialCapacity)
  • public HashMap(int initialCapacity, float loadFactor)
  • public HashMap(Map<? extends k, ? extends v> m) –> Cretes new HashMap with the specified Map.

To understand how hashmap works internally, let us consider we have an employee model class with a variable employee name,

Let us create employee object and put the employee object as key in HashMap and let us see how it gets inserted into HashMap.

 

From the above,

We have created 3 employee objects – e1, e2 and e3 with names Alpha, Beta and Charlie

Then we have put these values in hashmap with employee object as Key

HashMap<Employee, String> hm = new HashMap<Employee, String>();

hm.put(e1, “One”);
hm.put(e1, “Two”);
hm.put(e1, “Three”);

Now we have inserted the values into HashMap, we can see how they are populated in Buckets.

For our example, let us consider the hashcode values of

e1 – 756475 and it puts in bucket 2
e2 – 897865 and it puts in bucket 14
e3 – 756909 and it puts in bucket 2 again

First it checks the bucket, if any values are present. Since we do not have any values, it inserts the value in bucket 2.
It will insert hashcode first , i.e. 756475, next it will insert the key of HashMap – here the key is e1, then the value “One”, and last will be the pointer to next node. For now it will be null as no other elements are present to be populated in bucket.

Second we have the hashmap with element key e2 and value “Two”. It will check the bucket 14 and since no value is already present, it will populate the values in bucket 14.
hashcode of e2 – 897865, then the element Key, then element value, followed by the next value pointer, which is null for now.

Third, we have the hashmap with element key e3 and value “Three”. It will check for the bucket 2, and we have a value in it.

Here comes the key role for equals() method, it will check whether the e3 Key is unique when compared to e1. (e3.equals(e1)). It will return false as both objects are not equal. Then from the node which is kept as null when inserting first element, will point to next element i.e. e3.

In the same bucket as second entry, e3 will be populated with hashcode –  756909, Key – e3, value – Three and next will be kept as null until we get another value to be populated.

e1 entry which had null next now will point to e3 entry.

 

What happens when we insert duplicate Key?

Here we have created another employee object e4, with same value as of e1.

Employee e4 = new Employee(“Alpha”);

hm.put(e4, “Four”);

How as we discussed, it will calculate the hashcode for the object e4. The hascode is 756475 and it points to bucket 2.

But the bucket 2 already has more records available. So first will check for hashcode, if the inserting record hashcode and available record hashcode matches, then it will compare the Key. This is where equals() plays an important role.

In the above case, e1.equals(e4) which will return true as both objects are equal. Then the values of object e1 will be replaced with values of e4.

so now the hashbucket first entry will be of e4 values,

Important Keypoints:

  • HashMap uses hashcode() to identify the bucket where the record to be inserted
  • If a record is already available in the bucket, it will check for key (to check uniqueness) with equals() method, if it return true then the record will be replaced. If it false, new record will be inserted.
  • When more than one record is available in the bucket, it will have a next node which will point to the next available record in the bucket.

How does get() method work in HashMap?

Now let us try to retrieve an element from hashmap, let us retrieve e3,

hm.get(e3);

Now hashmap will use hashcode() and will identify the bucket in which element might be present. Next it will go to the bucket (In this case 2) and finds more than one record is available.

Now it will compare the key, if both the keys are matched then it will retrieve the value.

 

 

So When we try to get e3, first it will calculate the hashcode

hashcode() for Key e3 : 756909 and based on indexing to identify the bucket, it is calculated to be Bucket 2.

But Bucket 2, already has more than one record. Next the calculated hashcode will be compared to the inserted record in hashmap bucket 2. First it will compare 756909 with first record in hashmap that is 756475. Both are not equal, next will check the next node. Here the next node is pointing to another record. So it will go to the next record and will compare the hashcodes. 756909 and next record’s hashcode 756909 both are equal. Next will take the key of that record from bucket 2 and will compare with the key user requested. In this case, e3.equals(e3) which will return true.

Since both objects are equal and hashcodes are matching, that record will be retrieved from hashbucket and given to the user. This is how get method works.

Key Note:

If two objects are equal, their hashcode will always be same
If two hashcodes are same, that doesn’t mean both objects are equal.

Strings are Immutable | StringBuilder | StringBuffer

Strings are Immutable | StringBuilder | StringBuffer:

In this post, let us discuss about Strings, why Strings are immutable where as StringBuilder and StringBuffer are mutable.

 

What is Immutability?

When we assign a value to a String variable, that value can never be changed. That is known as immutability.

Strings can be created in 2 ways,

String S1 = “One”;

String S1 = new String(“One”);

What is the difference between these two ways of String creation?

String creation Way 1:

First let us see the type 1, i.e. String S1 = “One”;

For better understanding, let us create 3 strings

In general, Whenever a String is created all the values will be stored in StringPool. Here we have created 3 Strings so all these values – “One”, “Two” and “One” should be stored in StringPool.

Let us see how these above String values are Stored in StringPool.

 

As we can see the values – “One” and “Two” are stored in StringPool but another value of String S3 = “One” is not stored in StringPool. What actually happened?

When the values are Stored in StringPool when Strings are created in above mentioned way, When two or more strings has the same value only one of that such value will be stored in StringPool and the address of that value in StringPool will be referenced to String Variables.

So from above, since S1 and S3 has same value only one of such value is stored in StringPool and the address Addr1 will be referenced to S1 and S3

So the String variables will point to,

S1 = Addr1
S2 = Addr2
S3 = Addr1

How does “==” Work when Strings are created in above mentioned way?

The “==” works by comparing the address of the String variable rather than comparing the exact value of Strings. So in this case if we try to compare (S1==S3), Since both has same address it will
return True.

What if we concatenate the String? Will the value be replaced?

As we discussed, Strings are immutable. That is, once a value has been created that value will never change.
Consider this example,

If we concatenate String S1, what will happen?

S1 = “One” + “Three”;

Will the above statement replace the value One in StringPool? The answer is No.

Now we have concatenated the String, How the values will be at StringPool?

The new concatenated value will be inserted into StringPool and the String Variable S1 will point to new inserted value address – Addr3, Where as the value “One” remains unchanged.
This is the reason Strings are said to be Immutable.

Second way of Creating a String:

Another way of creating a String is using new Keyword, Let us create 3 strings for our understanding.

So we have created 3 Strings – S1,S2 and S3 and assigned the value – “One”, “Two” and “One” using new keyword.

How are these values stored in StringPool?

As you can see the difference, the value “One” is inserted again for the variable S3. Why?

Because the way we created String, We have used new keyword. When we create a String using new keyword, each String is considered as new value and it will be Stored in StringPool even though the same value might be available in StringPool.

So here, The String S1 will have Addr1 pointed to it, S2 will have Addr2 and S3 will have Addr3 – even though S1 and S3 has same value, since we used new keyword to insert the String – it inserted the “One” as new value and new address is given.

How does “==” Work when Strings are created in second String creation way?

Since each value is created newly and inserted in StringPool, The result will always be false for S1==S3 as both S1 and S3 have different addresses.

Why is StringBuilder and StringBuffer are mutable?

StringBuilder internally extends AbstractStringBuilder, it has a value which has an underlying working of Array. Since Arrays are mutable and StringBuilder is an Array wrapped class, it is mutable.

What if we perform Concatenation in StringBuilder?

It will not create a new value, instead it will replace the existing value with newly concatenated value

So what is the difference between StringBuilder and StringBuffer?

The only difference between StringBuilder and StringBuffer is – StringBuilder is not Synchronized (i.e. Not Thread Safe) where as StringBuffer is Synchronized (i.e.Thread Safe)

Performance:
When considering the performance, StringBuilder is faster than StringBuffer because, StringBuilder is not synchronized.

Coupling | Tight Coupling vs Loose Coupling | Examples

Coupling | Tight Coupling vs Loose Coupling | Examples

What is Coupling?
When one object is used by another object it is known as Coupling. In general, it is based on dependency. One object dependency over another object.

There are two types of Coupling,

  • Tight Coupling
  • Loose Coupling

First let us see about tight coupling,

Tight Coupling:

When one object is dependent very much over another object it is known as Tight Coupling. Let us understand with an Example.

For understanding this example, let us create an interface first,

We have a Job Interface with a method display in it.

Now to understand this example, let us create 2 classes. Doctor and Engineer which implements the Job Interface.

Doctor.java

Engineer.java

App.java

Now in main class,

This will give us the output,

So far so good, right?

Now let us consider the scenario, The requirement changes in future. We might have to add another professional for example Scientist. What we do now?

We need to create a class, implement job interface and override display method.

In App.java, we need to give reference to Scientist, add the Scientist variable to Constructor and create a new object and pass Scientist Object and then call display() method in App. java.

Too much of work right?

This is known as tight coupling. One object too much dependent and coupled with another object.

So how can we overcome this, here we are going to use concept of Loose coupling.

By this time, you might have guessed – Reducing the dependencies between object is known as Loose Coupling.

Now for the above same requirement with Doctor and Engineer, let us see how can we write the main class with Loosely Coupling method,

Loose Coupling:

Reducing the dependencies of one object with another object is known as Loose Coupling.

The above main method is re-written again with concept of Loose Coupling.

This code looks simpler when compared to Tight Coupled Code.

Instead of passing Doctor and Engineer objects directly, we have passed Job as reference.

During the run time we are passing the required object to perform the process. In this case, even if the requirement changes in future we do not have to make much changes for the above code.

Even when a new profession is introduced, example : Scientist. Now it is easy for us to make code changes without much change.

 

Frequently Performed Operations in List

Frequently Performed Operations in List

In our previous article, we had discussed about List interface, types of lists, internal working along with their advantages and disadvantages. (Please read here).

In this article we can discuss some of the most frequently performed list operations and which has to be remembered at all times.

Arrays.asList:

When we use Arrays.asList, it converts the array elements into a fixed size list. Let us see an example,

Now we have a fixed size list -> stringList.

What will be the output?

Now let us try to add an element “Echo” to the above list,

As a common expectation it should add the element to the list, But unfortunately we will get an exception when we try to add an element to the above list,

We will get the same exception when we try to remove an element from the above list, but why?

But, Why?

When we use Arrays.asList -> it returns a fixed size list which limits to perform add / remove operations.

Updating is possible:

Even if we have the limitation to add / remove an element, we can still update the list as the list size is not going to change.

Here is the sample code,

Now for other examples, let us create 2 lists,

We have 2 lists where 5 and 11 are common elements and we have 2 elements 90 in second list as duplicates.

Max and Min in the list:

How to find the maximum element and minimum element in the list ?

We can use ,

What is the list is empty or if it is a generic list when trying Collections to get min or max?

If the list is empty we will get NoSuchElementException and if the list is generic (list contains mix of string, integers etc…) it will throw ClassCastException.

How can we concatenate or add two lists?

Example, if we can to add both the lists intList1 and intList2 , we can use

This will combine all the elements to both lists together.

How to Concatenate or Add two lists avoiding duplicates?

There are two ways of doing this,

Type 1:

We can use streams to get distinct elements,

Type 2:

 

Replacing all the occurrences of a element in the list:

Consider in the intList2, we have element 90. Now if we want to replace all the occurrences of element 90 with 100 in list2, how can this be done?

This will replace element 90 to 100 in intList2.

How can we make a list Synchronized?

The lists are not thread-safe by default, suppose if we want to make the list threadsafe, we can use

SingletonList vs UnmodifiableList:

We have Collections.singletonList and Collections.unmodifiableList. So what is the difference between these two?

Collections.singletonList:  will take single element or object and makes it an immutable list with that single element or object.

Collections.unmodifiableList: Will make the list as an read-only list, when any add or remove operations are performed, it will throws UnSupportedOperationException