Java @ Desk: Core Java | Java at your desk

How to start Tomcat Server in Java

How to start Tomcat Server in Java

Tomcat server is started using the startup.bat file under bin folder. To start a Tomcat server from command prompt, user is required to hit the command startup.bat and tomcat server gets started in the new command prompt.

To start a server from Java code, its required to create a process of the batch file and execute the process. Below is the source code of the same.

The tomcat server path and the port is mentioned in the properties file along with the Java Path. Properies file is read in the batch file to set the values of Catalina Home and Java Home. If the values are not set in the environment variable for CATALINA_HOME & JAVA_HOME, then they are picked from properties file.

Here is the complete source code.

TomcatStart.java
package com.test;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class TomcatStartLocalCommand {
 public static void main(String args[]) throws IOException, InterruptedException {
  String command = "C:/Kumar/Documents/ChatBot/myStartUp.bat C:\\Kumar\\Documents\\ChatBot\\tomcat.properties";
  Process process = Runtime.getRuntime().exec(command);
  String ss = null;

  BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream()));

  System.out.println("Success:");
  while ((ss = stdInput.readLine()) != null) {
   System.out.println(ss);
  }
 }
}




myStartup.bat
@echo off
if not "%CATALINA_HOME%" == "" goto gotHome
set arg1=%1
echo Tomcat Properties Location is %arg1%
For /F "tokens=1* delims==" %%A IN (%arg1%) DO (
 IF "%%A"=="catalinaHome" set catalinaHome=%%B
 )
set CATALINA_HOME=%catalinaHome%
echo Catalina Home is %CATALINA_HOME%
if exist "%CATALINA_HOME%\bin\catalina.bat" goto gotHome

:gotHome
if not "%JAVA_HOME%" == "" goto gotJava
set arg1=%1
echo Tomcat Properties Location is %arg1%
For /F "tokens=1* delims==" %%A IN (%arg1%) DO (
 IF "%%A"=="javaHome" set javaHome=%%B
 )
set JAVA_HOME=%javaHome%
echo Java Home is %JAVA_HOME%
if exist "%JAVA_HOME%\bin\java.exe" goto gotJava


:gotJava
set "EXECUTABLE=%CATALINA_HOME%\bin\startup.bat"
call "%EXECUTABLE%"


tomcat.properties
catalinaHome=C:\Kumar\Softwares\apache-tomcat-8.0.38
javaHome=C:\Program Files\Java\jre1.8.0_111
port=8080

Types of Reference in Java - Strong, Weak, Soft, Phantom References

Types of Reference in Java - Strong Reference, Weak Reference, Soft Reference, Phantom Reference

Before diving into references, it’s important to know that Java has its own memory management system. The garbage collector in Java reclaims the memory whenever the application runs low on memory. The garbage collector can free the memory only from those objects which are eligible for garbage collection. This eligibility for garbage collection depends on the type of reference the object has. The command System.gc() can be used to request for garbage collection.

There are 4 types of references in Java:

1. Strong Reference
This is the normally used type of reference. Whenever we create a new object, we create a strong reference to that object. All objects which have strong references will never be garbage collected. By using strong references, we send a message to the garbage collector that the object is actively used it should not be garbage collected.
In the example below, the object strong1 is set to null and the GC is requested. However, since the object strong2 refers to strong1 and strong2 has a strong reference, therefore strong2 is not garbage collected.

Sample code:
private void strongReferenceTry() {
 Bar strong1 = new Bar();
 Bar strong2 = strong1; 

 System.out.println("Get the strong reference : "+ strong2);

 strong1 = null; // Removing strong reference
 System.gc(); // Requesting garbage collection

 System.out.println("After Removing strong reference and requesting Garbage Collection");
 System.out.println("Get the strong reference : "+ strong2);
}

Output:
Get the strong reference : Bar@7150bd4d
After Removing strong reference and requesting Garbage Collection
Get the strong reference : Bar@7150bd4d



2. Weak Reference
The objects which have weak references will be garbage collected in the next cycle of garbage collection. For example, Weak Hash Map in Java by default uses weak reference.
In the example below, you can see that once the strong reference to the object is removed, then the weak reference is also removed from the memory in the next GC cycle.

Sample code:
private void weakReferenceSample (){  

 Bar strong = new Bar(); // creating strong Reference
 WeakReference<Bar> weakReference = new WeakReference<Bar>(strong); //weak reference

 System.out.println("Get the weak reference : "+ weakReference.get());

 strong = null; // Removing strong reference
 System.gc(); // Requesting garbage collection

 System.out.println("After Removing strong reference and requesting Garbage Collection");
 System.out.println("Get the weak reference : "+ weakReference.get());
}

Output:
Get the weak reference : Bar@6bbc4459
After Removing strong reference and requesting Garbage Collection
Get the weak reference : null



3. Soft Reference
This type of reference also allows the garbage collection of objects. Soft reference is just like weak reference, with the difference that the objects having soft reference will not be garbage collected until and unless there is a memory crunch. This is unlike the case of weak references which will be garbage collected mostly in the next garbage collection cycle.
In the example below, even though there is no strong reference to the object, it still remains in the soft reference as the garbage collector does not remove it from the memory.



Sample code:
private void SoftReferenceSample (){
 
 Bar strong = new Bar(); // creating strong Reference
 SoftReference<Bar> softReference = new SoftReference<Bar>(strong); //soft reference

 System.out.println("Get the soft reference : "+ softReference.get());

 strong = null; // Removing strong reference
 System.gc(); // Requesting garbage collection

 System.out.println("After Removing strong reference and requesting Garbage Collection");
 System.out.println("Get the soft reference : "+ softReference.get()); 
}

Output:
Get the soft reference : Bar@6bbc4459
After Removing strong reference and requesting Garbage Collection
Get the soft reference : Bar@6bbc4459



4. Phantom Reference
This is a completely different concept. Calling get() on a phantom reference will always return null. When you construct a phantom reference, you must always pass it in a ReferenceQueue. Once the phantom reference is garbage collected, the object will be added into this ReferenceQueue, and thus, indicates when your object is garbage collected.
Phantom references have little use apart from helping us find when an object is garbage collected.

Sample code:
private void phantomReferenceSample (){

 ReferenceQueue<Bar> queue = new ReferenceQueue<Bar>();
 Bar strong = new Bar(); // creating strong Reference
 PhantomReference<Bar> phantomBar = 
 new PhantomReference<WeakReferance.Bar>(strong, queue); // creating phantom reference

 System.out.println("Get the phantom reference : "+ phantomBar.get());
 System.out.println("Phantom reference queue :  " + phantomBar.isEnqueued() );

 strong = null; // Removing strong reference
 System.gc(); // Requesting garbage collection

 System.out.println("After Removing strong reference and requesting Garbage Collection");
 System.out.println("Get the phantom reference : "+ phantomBar.get());
 System.out.println("Phantom reference queue :  " + phantomBar.isEnqueued() );
}

Output:
Get the phantom reference : null
Phantom reference queue :  false
After Removing strong reference and requesting Garbage Collection
Get the phantom reference : null
Phantom reference queue :  true

This post is written by Jerin Joseph. He is a freelance writer, loves to explore latest features in Java technology.

volatile keyword in java

The Keyword "volatile"

volatile is a keyword in java that is used with variables. By defining a variable as volatile, we say that all read and write operations made to this variable are done from the main memory rather than the local CPU cache (in case of other variables, the read and write operations are done via the local CPU cache for performance).

In a multi threaded application, each thread may cache the variables in its local cache, but the volatile variable will not be cached (even if the variable gets cached in its local stack, the value will be refreshed and will be in sync with the main memory value). And thus, by defining a variable as volatile, we make sure that all the reads to a variable will get the latest value of the variable.

Consider the scenario where three threads - TReader1, TReader2 and TWriter; accessing an integer variable counter. Both reader threads - TReader1 and TReader2 - just read the value of counter and TWriter writes value to it. If counter is not volatile, then, the reader threads read the value from their local cache and the writer thread would also write the value to its local cache, and would, at a later stage write it to the main memory.

Suppose the value of counter was 0 when all threads read the value and placed it in their respective local caches. The subsequent reads of the reader threads will be from their own local caches, and so, will be 0. Now let us assume that the writer thread updates the value of counter to 1. Since counter is not volatile the updated value will be written only to the local cache of the writer thread, and later, will be written to the main memory. However, in the current state, the reader threads would read the value of counter as 0 (from their corresponding local caches). This is not the desired behaviour.

Let us now define the variable counter to be volatile:
private volatile int counter = 0;


Here, the reader and writer threads will not keep the value in their local caches. Therefore, when the value of counter is updated to 1 by TWriter, the value is updated in the main memory itself, and the next read from the reader threads will give the updated value from the main memory. Thus, defining a variable as volatile ensures that all the threads always read the latest value of the variable in the memory.

So is defining a variable as volatile enough to make that variable synchronized?
The answer is NO. volatile is never a substitute for synchronization. Volatility just guarantees the visibility of the variable and NOT atomicity, whereas Synchronization (locking) guarantees both visibility and atomicity.

By visibility we mean that all the threads will get the latest form of the variable. In the above example, as you can see, all the threads get the latest value of counter in the subsequent reads.

As a simple illustration for atomicity, let us again consider the example above. Assume that both TReader1 and TReader2 read the value of volatile variable counter, and say both the reader threads get its value as 1. Now, say both increment this value by one, and then write it. However, you will notice that the value of counter which is written in the main memory is 2 and not 3! This is unlike the case of synchronization, where the value of counter would have been 3 after the update operation by both the threads, because of the locking mechanism.



When to use volatile
As you can clearly see, you can define a variable as volatile only:
i) When you are updating the reference and not performing some other operations
on the variable, and,
ii) In cases where different threads read and write the value of this variable
(to ensure that the reader threads get the latest value of the variable)

We should only use the keyword volatile when it is absolutely necessary to enforce the visibility of the variables. This is because there is a performance hit while using the volatile keyword due to:
a) Read and write of the variables being done to the main memory rather than the cache
b) It prevents instruction reordering (A performance enhancement technique used by JVM)

This post is written by Jerin Joseph. He is a freelance writer, loves to explore latest features in Java technology.

Difference between WeakHashMap vs HashMap

WeakHashMap in Java with example

WeakHashMap in java is an implementation of Map interface.

Reference in java are memory address where the created objects points in the memory. In a WeakHashMap, concept of Weak Reference is used.

As soon as you create an object in java and assign it to some variable, it becomes strongly reachable.

Weak reference object can somewhat be similar to object that has no memory references i.e. it can be garbage collected now.

Difference between WeakHashMap vs HashMap

In other Map implementations like a HashMap, the keys are strongly reachable. For example, if a HashMap has keys as Person class as shown below and if Person object is set to null, even after this if we will do map.get(Person) we will get the value from the memory since the keys are strongly referenced in a HashMap.

wm.put(person, person.getFirstName());
person = null;
System.gc();
System.out.println("Hash Map :" + wm.toString());

Output : Hash Map :{test.Person@12dacd1=John}

Compared to HashMap, WeakHashMap is the one which will remove its enteries as soon as the keys have no reference in the memory. For example, if a WeakHashMap has keys as Person class as shown below and if Person object is set to null, now if you do map.get(Person) we will get null out of it because the key has no reference (or rather weakly reachable).
wm.put(person, person.getFirstName());
person = null;
System.gc();
System.out.println("Weak Hash Map :" + wm.toString());

Output : Weak Hash Map :{}


Map<Person, String> wm = new WeakHashMap<Person, String>();
Person person = new Person();
person.setAge(25);
person.setFirstName("John");
wm.put(person, person.getFirstName());
  
Person person2 = new Person();
person2.setAge(35);
person2.setFirstName("Anderson");
wm.put(person2, person2.getFirstName());

System.gc();
System.out.println("Weak Hash Map :" + wm.toString());

person = null;
System.gc();
System.out.println("Weak Hash Map :" + wm.toString());


Running the above code gives us

Weak Hash Map :{test.Person@42719c=Anderson, test.Person@10385c1=John}
Weak Hash Map :{test.Person@42719c=Anderson}

Before nullifying the person object, WeakHashMap consists of both the enteries. Once the person object is nullified, garbage collector removed the object from the memory and since it is weakly referenced, WeakHashMap removed the entry for key person



String as a key for WeakHashMap

String is not suitable for WeakHashMap if used as a key. This is because, when a String object is created JVM creates the object in the String pool also. They may remain strongly referenced in the string pool even after you have nullified the reference.
Map<String, String> stringWeakHashMap = new WeakHashMap<String, String>();
String str1 = "Key 1";
String str2 = "Key 2";
  
stringWeakHashMap.put(str1, "Value 1");
stringWeakHashMap.put(str2, "Value 2");
str1 = null;
  
System.gc();
System.out.println("Weak Hash Map :" + stringWeakHashMap.toString());

After running the above code the output generated is

Weak Hash Map :{Key 2=Value 2, Key 1=Value 1}


It is clearly visible, since the string objects have strong reference due to string pool the key "str1" is not removed from the WeakHashMap

Restart Threads in Java using UncaughtExceptionHandler

Restart Threads in Java using UncaughtExceptionHandler

A lot of interview rooms listen to this question and a lot of candidates stop on a "No". Hope you have an elaborate answer after reading this post.

Threads have always been the most debated, misunderstood and under estimated component in Java. What makes this component even more mysterious is its ability to be controlled by the OS Scheduler of your underlying operating system. Threads are something that makes your code OS dependent and take away the ability of it to be "PLATFORM INDEPENDENT".

A very common interview question is can they be restarted. If you are handling the instantiation of your Thread,it cannot be restarted if it has finished its execution (terminated state). Done so, it throws a java.lang.IllegalThreadStateException exception.

public class ThreadState extends Thread {
 
 public void run(){
  System.out.println("I am in Run");
 }

 public static void main(String[] args) throws Exception{
  ThreadState threadState = new ThreadState();
  threadState.start();
  System.out.println(threadState.getStackTrace());
  Thread.sleep(100);
  
  System.out.println(threadState.getStackTrace());
  threadState.start();
  System.out.println(threadState.getStackTrace());
  
 }
}


Another direction this question could be answered is Thread Pools. You do not atomically handle thread starts when using Thread Pools. That logic is implemented by the thread Pool. Neither does the thread of a pool go to TERMINATED state when finished executing, it goes back to the pool and is made available for other tasks.

To add more to it, Threads cannot be exactly restarted but you can instantiate a new object of Thread and do so on your thread terminating condition. Most common reason threads can terminate is because of Exceptions. This can be achieved using UncaughtExceptionHandler Interface. It was introduced in Java 1.5 version.

Your interviewer might want an answer to a scenario which I quote now:
Let’s say you have a polling application which polls to check if an integer has a specific value. If you reach that specific value, your next task can start executing. You will have to keep re-polling until integer reaches that specific state. Below is the implementation:
class CustomExceptionhandler implements UncaughtExceptionHandler{

 public void uncaughtException(Thread paramThread, Throwable paramThrowable) {
  System.out.println("I have reached the Re Instantiation Of Thread");
  new PollingThread().start();
  System.out.println("Re Instantiation Of Thread completed and Thread started"); 
 } 
}


public class PollingThread extends Thread {
 
 public void run(){
  this.setUncaughtExceptionHandler(new CustomExceptionhandler());
  int randomIntvalue = new Random().nextInt(5) ;
  if(randomIntvalue > 3){
   System.out.println("Polling successfull...Int value = "+randomIntvalue);
   System.out.println("Polling state achieved");
  }else{
   System.out.println("Polling un- successfull...Int value = "+randomIntvalue);
   System.out.println("Application needs to Repoll");
   intdivideByZero = 1/0;
  }
 }
 
 public static void main(String[] args){
  System.out.println("I am starting to Poll now");
  new PollingThread().start();
 }
}


setUncaughtExceptionHandler() method sets the objects of concrete UncaughtExceptionHandler type on your Thread. uncaughtException method is invoked every time an exception occurs in your Thread Execution. I have re-instantiated my Thread and started it in this method. Note , I have re-instantiated my Thread and not restarted it. So Threads cannot be restarted but they can surely be re-instantiated at thread terminating condition.



The above application could go out of memory if the randomIntvalue variable never achieves its desired value. Or in logical terms, the poll never gets over. So this thought could also be presented with a ThreadPool. I have built a Thread Pool of capacity 10 using java.util.concurrent.ExecutorService. If the thread does not have an explicit uncaught exception handler set, and the thread's thread group (including parent thread groups) does not specialize its uncaughtException method, then the default handler'suncaughtExceptionmethod will be invoked.By setting the default uncaught exception handler, an applicationcan change the way in which uncaught exceptions are handled (such as logging to a specific device, or file) for those threads that wouldalready accept whatever behavior the system provided.

class CustomExceptionHandler implements UncaughtExceptionHandler{

 public void uncaughtException(Thread paramThread, Throwable paramThrowable) {
  System.out.println("I have reached the Re Instantiation Of Thread");
  PollingThread.submitThreadToPool(new PollingThread());
  System.out.println("Re Instantiation Of Thread completed and Thread started");
 }
}

public class PollingThread extends Thread {
 
 static ExecutorService executorService = Executors.newFixedThreadPool(10);
 
 public void run(){
  this.setUncaughtExceptionHandler(new CustomExceptionHandler());
  int randomIntvalue = new Random().nextInt(5) ;
  if(randomIntvalue > 3){
   System.out.println("Polling successfull...Int value = "+randomIntvalue);
   System.out.println("Polling state achieved");
   getThreadPool().shutdown();
  }else{
   System.out.println("Polling un- successfull...Int value = "+randomIntvalue);
   System.out.println("Application needs to Repoll");
   intdivideByZero = 1/0;
  }
 }
 
 public static void main(String[] args){
  Thread.setDefaultUncaughtExceptionHandler(new CustomExceptionHandler());
  System.out.println("I am starting to Poll now");
  executorService.execute(new PollingThread());
 }
 
 public static void submitThreadToPool(Runnable runnable){
  executorService.execute(runnable);
 }
 
 public static ExecutorService getThreadPool(){
  returnexecutorService;
  
 }

}


This post is written by
Komal Ahluwalia - Linkedin, Google Plus
She is a freelance writer, loves to explore latest features in Java technology.


Difference between notify vs notifyall in Java

Difference between notify vs notifyall in Java

Consider a basic Producer Consumer problem where we have 10 consumer threads and only 1 Producer thread. Producer doing some activity (for e.g. creating some singleton objects that will be used by all consumers). Hence all consumers has to wait till the singleton object is created by Producer.

Once producer finished the job of creating singleton object, it can notify the consumer. Now in this case, there are 10 consumers so all the 10 consumers need to be informed that the job is done and you may start processing. In this case we must go for notifyAll().

As explained,
1) notify() is used when a particular 1 thread needs to notify where all the threads will do a similar fashion of job.
2) notifyAll() is used when all the waiting threads needs to notify that have different purpose. In above case of creation of Singleton object, we need to use notifyAll()

In case of notifyAll(), even though the notification is sent to all to start processing, but each thread enters the RUNNING state in some particular random order. The order is defined by the JVM.

I have a scenario, where I have
a) NotifyThread - This thread sleeps for 100ms as soon as it starts. It can be assumed as a PRODUCER class.
b) WaitThread - As soon as this thread starts, it enters into wait state. There are 10 WaitThread that are started simultaneously. The wait is applied on a variable "synVariable".

As soon as NotifyThread sleep is over, it does notifyAll() which notifies all the 10 WaitThread that starts running in some particular random order which is decided by JVM.

I am facing a very weird issue in the code implemented below, where I have 10 Consumers and 1 Producer. When I am using notify() only 1 thread is notified while the rest 9 keep on waiting for infinite amount of time. I need help of the reader how to come out of this issue. Please use the comment section below for suggestions.

NotifyThread.java - There will be 1 object of NotifyThread.
package com.notifyall;

public class NotifyThread implements Runnable {

 @Override
 public void run() {
  try {
   Thread.sleep(100);
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
  synchronized (synVariable) {
   System.out.println("\n**********Notify Thread Started*********\n");
   synVariable.notifyAll();
  }
 }

 private String synVariable;

 public String getSynVariable() {
  return synVariable;
 }

 public void setSynVariable(String synVariable) {
  this.synVariable = synVariable;
 }
}


WaitThread.java - 10 threads will be created for this object.
package com.notifyall;

public class WaitThread implements Runnable {

 @Override
 public void run() {
  synchronized (synVariable) {
   try {
    System.out.println("WaitThread " + this.getThreadNumber() + " Started." +
      " Waiting for NotifyThread for Notification");
    synVariable.wait();
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  }
  System.out.println("WaitThread " + this.getThreadNumber() + " got Notified");
 }
 
 private String synVariable;

 public String getSynVariable() {
  return synVariable;
 }

 public void setSynVariable(String synVariable) {
  this.synVariable = synVariable;
 }
 
 private int threadNumber;

 public int getThreadNumber() {
  return threadNumber;
 }

 public void setThreadNumber(int threadNumber) {
  this.threadNumber = threadNumber;
 }

}


TestClient.java



package com.notifyall;

public class TestClient {

 public static void main(String args[]) {
  WaitThread[] waitThreads = new WaitThread[10];
  NotifyThread notifyThread = new NotifyThread();
  
  String synVariable = "synVariable";
  
  notifyThread.setSynVariable(synVariable);
  
  for(int i = 0 ; i < 10 ; i++) {
   waitThreads[i] = new WaitThread();
   waitThreads[i].setSynVariable(synVariable);
   waitThreads[i].setThreadNumber(i);
   new Thread(waitThreads[i]).start();
  }
  
  new Thread(notifyThread).start();
 }
}


Output - The Order of Notification may differ in order because it all depends on JVM which thread gets the notification first.
WaitThread 0 Started. Waiting for NotifyThread for Notification
WaitThread 1 Started. Waiting for NotifyThread for Notification
WaitThread 3 Started. Waiting for NotifyThread for Notification
WaitThread 4 Started. Waiting for NotifyThread for Notification
WaitThread 2 Started. Waiting for NotifyThread for Notification
WaitThread 5 Started. Waiting for NotifyThread for Notification
WaitThread 6 Started. Waiting for NotifyThread for Notification
WaitThread 8 Started. Waiting for NotifyThread for Notification
WaitThread 7 Started. Waiting for NotifyThread for Notification
WaitThread 9 Started. Waiting for NotifyThread for Notification

**********Notify Thread Started*********

WaitThread 9 got Notified
WaitThread 7 got Notified
WaitThread 8 got Notified
WaitThread 6 got Notified
WaitThread 5 got Notified
WaitThread 4 got Notified
WaitThread 1 got Notified
WaitThread 0 got Notified
WaitThread 2 got Notified
WaitThread 3 got Notified


To download source, click here

Overriding hashcode() and equals() in Java

Overriding hashcode() and equals() in Java

hashCode() and equals() are two methods that are defined in the class Object. As all the classes in java, by default, extend the Object class, we can override these methods in our classes.

Please note that we will be using the Student class defined below for illustration throughout this article.

In our example, we define a class Student, with both equals() and hashcode() methods overridden. Our requirement is that each student should have a unique id. Therefore, two student instances with the same id should be equal.

class Student{
 
 private Integer id;
 private String name;
 
 public Student(int id, String name) {
  this.id = id;
  this.name = name; 
 }
 
 @Override
 public boolean equals(Object obj){
  return ((Student)obj).id.equals(this.id);
 }
 
 @Override
 public int hashCode(){
  return id.hashCode();
  
 }

        @Override
 public String toString(){
  return id + "  " + name;
 }
}


equals()
The equals() method compares two objects to test their equality. Java recommends to override equals()method, if the equality is going to be defined by some other business logic. As per our requirement, two students with same id should be equal. So here, we override the equals()(as well as hashCode()) method to implement this action. If we do not override equals(), then the default implementation of equals() will be used.

Default implementation of equals()
The default implementation of equals() tests whether the object references of the two objects being compared are equal— i.e., if both the objects being compared are the exact same object. Its functionality is the same as the "==" check on two objects, which checks the value (i.e., memory address in the heap) of the two objects.

Let us now see how the following code works for the class Student defined above:
Student std1 = new Student(1, "jerin");
Student std2 = new Student(1, "jerin");
System.out.println("By == Check: " + (std1 == std2));
System.out.println("By overridden equals check: " + std1.equals(std2));


Output:
By == Check: false
By overridden equals check: true

As you can see, the overridden equals() method returns true, unlike its default implementation, where, like the "==" check, it would return false.
Internally, Java uses the equals() method to check the equality of two objects.
Say we place a Student object into a collection of Students. All the Students in this collection will have a unique id. At a later stage, say we need to remove a Student object from this list. We may not have the exact instance of the Student object placed in the list, but we have a unique id associated with each Student instance, based on which we can remove the respective Student object.



Consider the following sample code:
List<Student> studentList = new ArrayList<Student>();
studentList.add(new Student(1 , "Jerin"));
studentList.add(new Student(2 , "Joseph"));
studentList.add(new Student(3 , "Mark"));
studentList.add(new Student(4 , "Antony"));
   
Student studentJerin = new Student(1, "Jerin");
studentList.remove(studentJerin);
 
System.out.println(studentList);


Here, we pass the instance of Student to be removed from the list. The list internally checks whether the passed object is present or not based on the equals() method, and if it is, removes it from the list.

If equals is not overridden, then the output is:
[1  Jerin, 2  Joseph, 3  Mark, 4  Antony]

Explanation: In case of the default equals() implementation, the check is made for the exact instance of Student. In the example above, since we pass a different instance of Student, it will not find the second instance of Student "Jerin" in the list (even though it has the same id as the instance being checked for), and hence will not remove it from the list.

If equals is overridden correctly (as shown in Student class above), then the result is:
[2  Joseph, 3  Mark, 4  Antony]

Explanation: The overridden equals() method in our class equates two instances of Student based on their id. Therefore, it will find both instances of "Jerin" based on the same id and will remove both these objects from the list.

Contracts to be kept in mind while overriding equals:
1. Reflexive: For any non-null reference value x, x.equals(x) must always return true.
2. Symmetric: For any non-null reference values x and y, x.equals(y)must return true if and only if y.equals(x) returns true.
3. Transitive: For any non-null reference values x, y, z, if x.equals(y)returns True and y.equals(z)returns true, then x.equals(z)must also return true.
4. Consistent: For any reference values x and y, multiple invocations of x.equals(y) consistently return true or consistently return false.
5. For any non-null reference value x, x.equals(null) should return false.




hashCode()

hashCode() is used to return an integer value which is used in hashing based collections, such as a HashMap. In hashing based collections, the data is stored in buckets.

Basic working of hashing based algorithms:
Hashing based algorithms uses a set of buckets to keep the objects. Let us consider a simple example where we have 100 paper strips (analogous to Student Objects), with a student name and grade written on each of it. Say we have a total of ten grades – one through ten -and we have one bucket for each grade; i.e., a total of 10 buckets. We will place these 100 paper strips in the buckets based on the grade, i.e., grade 1 bucket will have all the papers of grade 1 students, and so on. Now, say we get a piece of paper with the student name and grade and we have to find the student. First, we will find the bucket using the grade (analogous to finding the hashbucket using the hashcode), and then look into the bucket to get the student based on the student name (analogous to finding the object from the bucket using equals() method).

Whenever we put an object into a hash based collection , we first find the bucket into which we need to place the object based on the hashcode value, and then place the object in that bucket. Whenever we need to find a particular object, we first need to find the bucket into which it was placed. It’s this hashcode value that is used to find the appropriate bucket, after which we can search for the particular object inside the bucket based on the equals() method. So, to retrieve objects correctly from the hash based collections we need to implement both hashCode() and equals() methods correctly.

Default implementation of hashCode()
By default, hashCode() is generally implemented by converting the internal address of the object into an integer. However, it is jvm specific. For most cases, the hashcode of different objects will return different values.
Just like the equals() method, if we do not override the hashCode() method correctly, we may not be able to retrieve a particular object placed in a collection.

Contracts to override hashCode():
1. Consistency: Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer
2. If two objects are equal according to the equals() method, then the hashcode must also be same for both objects

Conclusion
Throughout the collection framework, java uses equals() to check for the equality of two objects, and hashcodes to find the hashbuckets whenever we use collections that use hashing. Therefore, whenever we need to keep a value in a collection, we must always override the equals() and hashCode() methods correctly.

While overriding equals() and hashCode() methods, always keep the following in mind If two objects:
1. Have true for equals() , then they should also have same the same hashcode.
2. Have the same hashcode, they need not return true for equals()(as different objects can have the same hashcode, ie., multiple objects can be in the same bucket)
3. Have different hashcodes, then, they are always unequal.

Important Note:
If we use unmutable objects as the key in hashing based maps, we need to override the hashCode() and equals() methods of the object correctly. If any change in the state of the object violates the above said contract, we may not be able to retrieve the correct value from the map using the key. As a practice, it is advisable not to use any field for the calculation of hashcode, which is not used in the equals() method. This is because, in a later stage, the field that is used only in hashcode may change, and hence will create a different hashcode for the same object based on equals(). In such a scenario, two objects that are equal based on equals() check will have different hashcodes, and hence, will point to different buckets, finally resulting in us not being able to find this object.

This post is written by Jerin Joseph. He is a freelance writer, loves to explore latest features in Java technology.