Sunday, July 22, 2012

Serialization with respect to Inheritance

<<Previous


  • If the parent is Serializable then every child is by default Serializable that is Serializable nature will be inherited from parent to child.

package com.javamonkeys.serialization;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

class Animal implements Serializable{
 int i=10;
}
class Tiger extends Animal{
 int j=20;
}
public class SerializeInheritExample {
 public static void main(String[] args)throws IOException, ClassNotFoundException {
  Tiger t = new Tiger();
  FileOutputStream fiOutputStream = new FileOutputStream("D:\\serializablefile.ser");
  ObjectOutputStream oStream = new ObjectOutputStream(fiOutputStream);
  oStream.writeObject(t);
  
  FileInputStream fileInputStream = new FileInputStream("D:\\serializablefile.ser");
  ObjectInputStream oInputStream = new ObjectInputStream(fileInputStream);
  Tiger tig = (Tiger)oInputStream.readObject();
  System.out.println(tig.i+"......."+tig.j);

 }

}
Output: 10…….20

  • Even though parent is not Serializable and its child class is Serializable, At the time of serialization if any variable inheriting from non Serializable parent then JVM ignores original value and default value will be sent to the file.
  • At the time of de-serialization JVM checks is there any parent class is non Serializable or not.  If any parent is non Serializable then JVM creates an object of that class and shares its instance variables to the current object.
  • For creating object of non Serializable parent JVM always invokes no-argument constructor.  Hence every non Serializable parent should compulsory contain no-argument constructor otherwise we will get runtime exception InstantiationException.

package com.javamonkeys.serialization;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

class Animal {
 int i=10;
 Animal(){
  System.out.println("Animal class constructor");
 }
}
class Tiger extends Animal implements Serializable{
 int j=20;
 Tiger(){
  System.out.println("Tiger class constructor");
 }
}
public class SerializeInheritExample {
 public static void main(String[] args)throws IOException, ClassNotFoundException {
  Tiger t = new Tiger();
  t.i=100;
  t.j=1000;
  FileOutputStream fiOutputStream = new FileOutputStream("D:\\serializablefile.ser");
  ObjectOutputStream oStream = new ObjectOutputStream(fiOutputStream);
  oStream.writeObject(t);
  
  System.out.println("Deserialization process started");
  FileInputStream fileInputStream = new FileInputStream("D:\\serializablefile.ser");
  ObjectInputStream oInputStream = new ObjectInputStream(fileInputStream);
  Tiger tig = (Tiger)oInputStream.readObject();
  System.out.println(tig.i+"......."+tig.j);

 }

}
Output:

Animal class constructor
Tiger class constructor
Deserialization process started
Animal class constructor
10.......1000


Customized Serialization

<<Previous                                                                    Next>>

package com.javamonkeys.serialization;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

class User implements Serializable{
 transient UserDetails ud = new UserDetails();
}
class UserDetails implements Serializable{
 int udId=10;
}

public class ObjectGraphExample {
 public static void main(String[] args)throws IOException,ClassNotFoundException {
  User user = new User();
  FileOutputStream fiOutputStream = new FileOutputStream("D:\\serializablefile.ser");
  ObjectOutputStream oStream = new ObjectOutputStream(fiOutputStream);
  oStream.writeObject(user);
  
  FileInputStream fileInputStream = new FileInputStream("D:\\serializablefile.ser");
  ObjectInputStream oInputStream = new ObjectInputStream(fileInputStream);
  User usr = (User)oInputStream.readObject();
  System.out.println(usr.ud.udId);
 }

}


  • During Serialization there may be chance of loss of information because of transient variable.
  • In the above program before serialization we can access udId value but, after de-serialization we can’t access udId value. Because in the serialization process it will save null.  We will get NullPointerException in the line 27.
  • We can recover this lost information by using Customized Serialization.
  • We can achieve Customized Serialization by using following two methods.
private void writeObject(OutputStream os)
  • This method will be executed automatically at the time of Serialization.  Hence if we need to perform any extra activity at the time of serialization, we have to define the logic inside this method.
private void readObject(InputStream is)
  •  This method will be executed at the time of time of de-serialization automatically.  At the time of de-serialization if we need to perform any extra activity, we have to define the logic inside this method.
  • We have to keep these two methods in the corresponding class of Serialized object that is, at the time of User object serialization if we want to perform any extra activity we have to define these two methods in the User class.


package com.javamonkeys.serialization;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
class UserDetails{
 int udId=10;
}
class User implements Serializable{
 transient UserDetails ud = new UserDetails();
 private void writeObject(ObjectOutputStream os)throws IOException{
  os.defaultWriteObject();
  int k = ud.udId+100;//encrypting using some algorithm
  os.writeInt(k);
 }
 private void readObject(ObjectInputStream is)throws IOException, ClassNotFoundException{
  is.defaultReadObject();
   ud = new UserDetails();
  int k=is.readInt();
  //System.out.println(k);
  ud.udId=k-100;//Decrypting using the same algorithm used in above method.
 }
}


public class CustomizedSerializationExample {
 public static void main(String[] args)throws IOException, ClassNotFoundException {
  User user = new User();
  System.out.println(user.ud.udId);
  FileOutputStream fiOutputStream = new FileOutputStream("D:\\serializablefile.ser");
  ObjectOutputStream oStream = new ObjectOutputStream(fiOutputStream);
  oStream.writeObject(user);
  
  FileInputStream fileInputStream = new FileInputStream("D:\\serializablefile.ser");
  ObjectInputStream oInputStream = new ObjectInputStream(fileInputStream);
  User usr = (User)oInputStream.readObject();
  System.out.println(usr.ud.udId);
 }

}




Object Graphs

<<Previous                                                                          Next>>

  • Whenever we serialize an object, the set of all objects which are reachable from that object will be serialized automatically.  This group of objects are called object graph.
  • In the object graph every object should be Serializable otherwise, NotSerializableException will come.
Example:

package com.javamonkeys.serialization;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

class User implements Serializable{
 UserDetails ud = new UserDetails();
}
class UserDetails implements Serializable{
 UserAddress ua = new UserAddress();
}
class UserAddress implements Serializable{
 int uaId=10;
}
public class ObjectGraphExample {
 public static void main(String[] args)throws IOException, ClassNotFoundException {
  User user = new User();
  FileOutputStream fiOutputStream = new FileOutputStream("D:\\serializablefile.ser");
  ObjectOutputStream oStream = new ObjectOutputStream(fiOutputStream);
  oStream.writeObject(user);
  
  FileInputStream fileInputStream = new FileInputStream("D:\\serializablefile.ser");
  ObjectInputStream oInputStream = new ObjectInputStream(fileInputStream);
  User usr = (User)oInputStream.readObject();
  System.out.println(usr.ud.ua.uaId);
 }

}

Note: In the above example User, UserDetails and UserAddress should be serialized otherwise we will get NotSerializableException.


Serialization and De-serialization

Serialization: -
  • The process of saving state of an object to a file is called serialization.  But strictly speaking serialization is the process of converting an object from java supported form to either file supported form or network supported form.
  • By using FileOutputStream and ObjectOutputStream classes we can achieve serialization.



De-serialization: -
  • The process of reading state of an object from a file is called de-serialization.  But strictly it is process of converting an object from file supported form or network supported form to java supported form.
  • By using FileInputStream and ObjectInputStream classes we will achieve de-serialization.



Example:
Class to be serialized:

package com.javamonkeys.serialization;

import java.io.Serializable;

public class User implements Serializable {
 private String userName;
 private String passWord;
 public User(String userName, String passWord) {
  this.userName = userName;
  this.passWord = passWord;
 }
 public String getUserName() {
  return userName;
 }
 public void setUserName(String userName) {
  this.userName = userName;
 }
 public String getPassWord() {
  return passWord;
 }
 public void setPassWord(String passWord) {
  this.passWord = passWord;
 }
}
Main Class:

package com.javamonkeys.serialization;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class SerializableExample {
 public static void main(String[] args)throws IOException, ClassNotFoundException {
  String userName="javamonkey";
  String passWord="password";
  User user=new User(userName, passWord);
  FileOutputStream fiOutputStream = new FileOutputStream("D:\\serializablefile.ser");
  ObjectOutputStream oStream = new ObjectOutputStream(fiOutputStream);
  oStream.writeObject(user);
  
  FileInputStream fileInputStream = new FileInputStream("D:\\serializablefile.ser");
  ObjectInputStream oInputStream = new ObjectInputStream(fileInputStream);
  User usr = (User)oInputStream.readObject();
  System.out.println("User name:"+usr.getUserName());
  System.out.println("Password:"+usr.getPassWord());
 }

}



  • User is class which is to be serialized. In the SerializableExample class lines 14, 15 and 16 represents the serialization process and lines 18, 19 and 20 represents the de-serialization process. That is in the lines  14, 15 and 16  we are saving the state of a User object to the file called serializablefile.ser. Here .ser extension represents the Serializable file. If we open the file we can’t understand what is there in the file because it is file supported form. After de-serializing we are printing the results that can be understandable. That means after de-serializing object is converted to java understandable form.

  •  We can perform serialization process only on Serializable objects.
  •  An object is said to be Serializable if and only if the corresponding class implements Serializable interface.
  • Serializable interface present in java.io package and doesn’t have any method.  It is a marker interface.
  • If we try to serialize a non Serializable object (class that not implemented Serializable), then we will get NotSerializableException, it is a Runtime Exception.
transient:-
  • At the time of Serialization if we don’t want to send the value of any particular variable to meet security constraints, we have to declare such type of variable as transient.
  • transient means not to Serialize.
  • At the time of serialization process JVM sends the default values instead of original values if we declare that particular variable as transient.
  • Static variables are not part object, these are the part of class hence, and static variables won’t participate in the serialization process.  Even though we declare static variables as transient there will be no difference.
  • Final variables will not change to default values even if we make them as transient.
  • The below table illustrates the different possible combinations of inputs and outputs with the above example (change the types of variables in the User class not in the Main class).

Declaration
Output

String userName=”monkey”
String passWord=”password”


userName: monkey
password: password

transient String userName=”monkey”
String passWord=”password”


userName: null
password: password

String userName=”monkey”
transient static String passWord = “password”


userName: monkey
password: password

transient final String userName=”monkey”
transient String passWord=”password”


userName: monkey
password: null

transient  static String userName=”monkey”
transient  final String passWord=”password”


userName: monkey
password: password


Tuesday, July 17, 2012

Java 7

Hibernate

Hibernate Caching Techniques


While working with Hibernate web applications we will face so many problems in its performance due to database traffic. That to when the database traffic is very heavy. Actually hibernate is well used just because of its high performance only. So some techniques are necessary to maintain its performance. Caching is the best technique to solve this problem.  It is same as browser cache.  Whenever the request placed for one resource, it will hit the database and loads the data from the database. If the request is for the same resource first it will check in the hibernate cache, if it is available then it won’t hit the database.  It retrieves the data from the cache only.  So the database calls will decrease and the response time increases.
We have 2 types of cache in hibernate.
  1. First level cache.
  2. Second level cache.
1). First level cache:-
  • First-level cache is associated with the Session object.  Hibernate uses this cache by default. No need to enable the first level cache explicitly and we can’t disable first level cache also.
  • Most commonly session object is associated with the Transaction. That is we will create the session object per transaction and close the session after completing of that transaction.
  • It minimizes the database calls that are present in that particular session that is in particular transaction.
  • In this instead of calling database for every modification on that particular entity object in that particular transaction, it updates the entity object at the end of that particular transaction.
Example: 
Consider the example that; there is Customer.java(entity) with the customerId, customerName as properties and there is corresponding table tbl_customer with customer_id and customer_name columns.

hibernate.cfg.xml

        
com.mysql.jdbc.Driver
root
jdbc:mysql://localhost:3306/test
root
org.hibernate.dialect.MySQLDialect
true



Entity Class:
package com.javamonkeys.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="tbl_customer")
public class Customer {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="customer_id")
private Integer customerId;
@Column(name="customer_name")
private String customerName;
public Integer getCustomerId() {
 return customerId;
}
public void setCustomerId(Integer customerId) {
 this.customerId = customerId;
}
public String getCustomerName() {
 return customerName;
}
public void setCustomerName(String customerName) {
 this.customerName = customerName;
}

}
Main Program:
package com.javamonkeys;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import com.javamonkeys.entity.Customer;
public class MainProgram {
public static void main(String[] args) {
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Session session = sessionFactory.openSession();
try{   
Transaction tnxn = session.beginTransaction();
//trying to get the Customer object with customerId is 1.
//assuming that already there is customer info with the id 1.
Customer customer1 = (Customer)session.get(Customer.class,1);
Customer customer2 = (Customer)session.get(Customer.class,1);
Customer customer3 = (Customer)session.get(Customer.class,1);
//trying to update the same object multiple times.
customer1.setCustomerName("javamonkey ");
session.update(customer1);
session.update(customer1);
tnxn.commit();
}catch(Exception e){
e.printStackTrace();
}finally{
session.close();
}
}

}
         Assume that there is a record in the database ‘test’ with the customerId 1 in the tbl_customer table. In the line numbers 15, 16, 17 we are trying to retrieve the customer object from the database with id 1. In the three lines we are trying to get the same record. Hibernate hits the database in the line 15, but in the 16 and 17 line there will be no database call. That means it gets that same object from the first-level cache, as these three statements are the part of only one transaction and trying to get only one row from the database.  Hibernate intelligently detects that the minimum number of queries needs to be run.

        In the lines 20 and 21 we are trying to update the same object twice.  In this case if the name in the database is “javamonkey” hibernate won’t call database even one time. If the name is different than “javamonkey” then only once it hits the database to update the record.

Need of second level cache:

Problem with the first level cache is it is limited to session only.  How many sessions are opening, that many times hibernate hits the data base.  Alternatively we can minimize the database calls by putting the data in the session for the lookup values (data that won’t change frequently).  But consider there are 1000 users who are using the same application, then 1000 database calls for retrieving the same data. 

Say for example we have countries table, we need the countries values for entire application and those never change.  If we put these map or list in the session, to retrieve the counties map or list, there are 1000 database calls if we have 1000 users. 

Can’t we make only one database call and use those countries values for entire application…?

Yes, we can make only one database call and we can use those countries values for entire application, across users even with different applications also.  For this hibernate provides a powerful mechanism called second-level cache.

2). Second level cache:-

  • Second-level cache always associates with the Session Factory object.
  • As Session Factory object is only one for entire application, the data saved in the second level cache will be available for entire application.
  • It doesn't cares how many sessions are there, how many transactions are there in the application.  The data is available for all the transactions.
  • Here we can use query level cache also to cache the particular query results in the second level cache.
  • It never expires until the application is in running state.
  • By default the second level cache is set to false.  We can enable and disable as per our requirement.
  • For example if we are retrieving the data with the id 1 in different sessions.  In this case if second level cache is enabled; hibernate hits the data base only once.  For the next time on-wards it will search the data whether present in the second level cache, if it is there it won’t hit the database just it will pull the data from there.
  • It should be used for the lookup values that is, the values won’t change frequently.
  • We will take the Countries table contains the all country ids and country names in that table, Corresponding entity class is Countries.java and mapping file is Countries.hbm.xml (If you are not using the annotations).
Configuring Second level cache:
  • We need to add the following properties in the hibernate.cfg.xml to activate the second level cache.
true
org.hibernate.cache.EhCacheProvider
  • In the line 1 we are telling the hibernate to use the second level cache.
  • In the line 2 we are specifying the cache provider class.  We can implement the second level cache using different cache providers.  Those are
                    1.  EhCache (Easy Hibernate Cache)
                              2.  OSCache (Open Symphony Cache)
                        3.  Swarm Cache
                    4.  JBoss Tree Cache
  • Each implementation has its own advantages and disadvantages.
  • Here I am using EhCache. To use this EhCache we need to download the ehcache-core-.jar file and need to add this jar to the application build path.
  • To make the entity to be cacheable in second level cache, we need to add the annotation @Cacheable, @Cache below the @Entity annotation.
Entity class:

package com.javamonkeys.entity;
import javax.persistence.Cacheable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
@Entity
@Table(name="countries")
@Cacheable
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
public class Countries {
 @Id
 @GeneratedValue(strategy=GenerationType.AUTO)
 @Column(name="country_id")
 private Integer countryId;
 @Column(name="country_name")
 private String countryName;
 public Integer getCountryId() {
  return countryId;
 }
 public void setCountryId(Integer countryId) {
  this.countryId = countryId;
 }
 public String getCountryName() {
  return countryName;
 }
 public void setCountryName(String countryName) {
  this.countryName = countryName;
 }
}
By adding the @Cacheable annotation we are telling that hibernate that, this entity is cacheable and this entity has to consider for caching. 
By adding the @Cache we will configure the caching strategy. This annotation takes a parameter called usage where we can specify the caching strategy by using the enumeration. In hibernate, second-level cache we have four type of caching strategies. 
CacheConcurrencyStrategy.READ_ONLY: It’s the basic level of cache. This tells that the entity is read only. It is not going to write the data to the database. It is useful for the data that read frequently but never updated. It’s very simple. In this case hibernate doesn’t check whether update takes place, removing the cache or not. As it is read only, it the data is there in the cache it will provide that data from the cache for the application. For example we have the countries table and Countries Entity, in this case we will read data from database but we won’t update the Countries information as it is fixed.
CacheConcurrencyStrategy.READ_WRITE: It’s used whenever the data needs to be updated. It will check whether data is modified by application, so that we can get the modified data from the cache. That means whenever the data updated in the database hibernate updates the data in the cache also.
CacheConcurrencyStrategy. NONSTRICT_READ_WRITE: It is same as the read write strategy. But not strictly check the data modified or not in the application. 
CacheConcurrencyStrategy. TRANSACTIONAL: It is very strict about the data changes in the application or changes by other application. It checks the data whether it is modified or not for every transaction. It is almost same as session level cache. 
It is better to go for the READ_WRITE strategy.
  •  If you are not using the annotations we need to configure the caching strategy in the hbm file of that particular entity as follows.
hbm file:


    
                
            
            
        
        
            
        
       



  • In the line 3 we have configured the caching strategy to read-write strategy.

package com.javamonkeys;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import com.javamonkeys.entity.Countries;
public class MainProgram {
 public static void main(String[] args) {
  SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
  Session session=sessionFactory.openSession();
  Transaction tnxn = session.beginTransaction();
  Countries country = (Countries)session.get(Countries.class, 113);
  tnxn.commit();
  session.close();
  Session session1=sessionFactory.openSession();
  Transaction tnxn1 = session1.beginTransaction();
  Countries country1 = 
Countries)session1.get(Countries.class, 113);
  tnxn1.commit();
  session1.close();
 }
}
In the line number 12 we are retrieving the country with country id 113. And again we are retrieving the same data in the line number 17, but they are different sessions and different transactions. Generally hibernate has to hit the database for two times at line 12 and 17 but, As we implemented the second-level cache for Countries entity hibernate hits the database at line 12 only once. In the line 17 it won’t retrieve the data from the database instead, it will pull the same data from the second-level cache as it is already there in the cache. Even if I have 1000 places where the same data is required in the application, hibernate hits the database only once and used the same data from the cache will be used across the users. We are saving the 999 database calls in this case which has big impact of performance of application as well as database. 
Up to here everything is ok. But if we use the queries to retrieve the data from the database then this technique doesn’t work. You will wonder why this is not working and hitting the database two times to retrieve the data.
package com.javamonkeys;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import com.javamonkeys.entity.Countries;
public class MainProgram {
 public static void main(String[] args) {
  SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
  Session session=sessionFactory.openSession();
  Transaction tnxn = session.beginTransaction();
  String hql_query = "from Countries where countryId=:countryId";
  Query query = session.createQuery(hql_query);
  query.setInteger("countryId", 113);
  query.list();
  tnxn.commit();
  session.close();
  Session session1=sessionFactory.openSession();
  Transaction tnxn1 = session1.beginTransaction();
  String hql_query1 = "from Countries where countryId=:countryId";
  Query query1 = session1.createQuery(hql_query1);
  query1.setInteger("countryId", 113);
  query1.list();
  tnxn1.commit();
  session1.close();
 }

}
In the above case, in the output we can see two sql statements that are used to retrieve the data from the database with the country id 113 at line 16 and 24. To use the second level cache in this case we need to use the query cache technique. 
3. Caching the queries: - 

  • Query cache always use second level cache only. So if we want to use query cache we need to enable the second-level cache also.
  • Queries won’t cached by default. We need to tell hibernate explicitly to cache the queries. 
Configuring query cache: 

  • To configure the query cache we have to add the following line in the hibernate.cfg.xml including with the second level cache configuration lines as follows.
true 
org.hibernate.cache.EhCacheProvider 
true 

  • First two line to enable the second level cache and third line for enabling the query cache.
  • To cache the particular query we have to set query object cacheable for that we have to set property like query.setCacheable(true).

package com.javamonkeys;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import com.javamonkeys.entity.Countries;
public class MainProgram {
public static void main(String[] args) {
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Session session=sessionFactory.openSession();
Transaction tnxn = session.beginTransaction();
String hql_query = "from Countries where countryId=:countryId";
Query query =session.createQuery(hql_query).setCacheable(true);
query.setInteger("countryId", 113);
query.list();
tnxn.commit();
session.close();
Session session1=sessionFactory.openSession();
Transaction tnxn1 = session1.beginTransaction();
String hql_query1 = "from Countries where countryId=:countryId";
Query query1 = session1.createQuery(hql_query1).setCacheable(true);
query1.setInteger("countryId", 113);
query1.list();
tnxn1.commit();
session1.close();
}

}
In the lines 14 and 22 we have set that query to be cached. Now it hits the database only once when the line 14 got executed. When it executes line 22, as it set to cacheable in the line 22 first it will check the result in the query cache if it is there it will get the result from there only. 
But we need to set this flag to true in all places where we are using that particular query in the application otherwise it won’t check in the query cache.

Saturday, July 14, 2012

Customized Exception Handling by using try, catch

<<Previous                                                                                            Next>>
  1. We can handle exceptions explicitly by using try, catch.
  2. The risky code (Where there may be rising of exceptions) we have to keep in try block and corresponding handling code we have to take inside the catch block.
  3.  If any exception is raised in try block then corresponding catch block will be executed to handle that exception.  After execution of catch block the rest of the code will be executed normally and it will become graceful termination of program.
  4. We will use the try, catch blocks as follows.                                          
try {
     Risky code;
} catch (x e) {
    Handling code;
} 
Example1: -
class Test{
public static void main(String args[]){
System.out.println("statement 1");
System.out.println(10/0);
System.out.println("statement 3");
}
}
OutPut:
statement 1
Abnormal termination
In the line 4 ArithmeticException exception will come.

Example2: -

class Test{
public static void main(String args[]){
System.out.println("stmt 1");
try{ 
System.out.println(10/0);
}catch(ArithmeticException e){
System.out.println(10/2);
}
System.out.println("stmt 3");
}
}
Output:

stmt1
5
Stmt 3
Normal termination

Control Flow in try, catch: -

try {
statement1;
statement2;
statement3;
} catch(X e){
statement4;
}
statement5;
Case1: If there is no Exception.
            1,2,3,5               Normal termination
Case2: If an exception is raised at statement2 and corresponding catch block has matched.
           1, 4, 5                 Normal termination
Case3: If an Exception is raised at statement2 and corresponding catch block has not matched.
    1                        Abnormal termination
Case4:  Exception rose at statement4.
            It’s always abnormal termination of program.
Case5: Exception rose at statement5.
           Abnormal termination of program.

Try with multiple catch blocks: -

The way of handling an exception is varied from exception to exception, compulsory we have to write the separate catch block for every exception.  Hence try with multiple catch blocks is possible and it is recommended to use.

try {
Risky code;
} catch (ArithmeticException e) {
Handling code for ArithmeticException;
} catch (IOException e) {
Handling code for IOException;
} catch (NullPointerException e) {
Handling code for NullPointerException;
} catch (Exception e) {
Default exception handling code;
}
If try with multiple catch blocks present then, the order of catch blocks is very important.  It should be from child to parent but not parent to child.


Examples:

try{
}catch (ArithmeticException e){
//
}catch (Exception e){
//
}
The above one is correct.

try{
} catch (Exception e){
//
} catch (ArithmeticException e){
//
}
CE: java.lang.ArithmeticException has already caught.

Method to display Exception Information:-

Throwable class defines the following methods to print Exception information or Error Information.
1. printStackTrace()
This method prints Exception information in the following format.
Name of Exception: Description
Stack trace
2. toString()
This method prints Exception information in the following format.

Name of Exception: Description
3. getMessage()
This prints only description of Exception.
try {
    System.out.println (10/0);
} catch (ArithmeticException e){
    e.printStackTrace ();
    System.out.println (e); or System.out.println (e.toString ());
    System.out.println (e.getMessage ());
}
O/P for the line 4: ArithmeticException: /by zero at main()
O/P for the line 5: ArithmeticException: /by zero
O/P for the line 6: /by zero

Note:  Default exception handler always use printStackTrace() method to display Exception information.

Exception Hierarchy and Types of Exceptions

<<Previous                                                                Next>>
Throwable acts as a root for the entire Exception hierarchy.  This class contains the following two child classes.
  1. Exception: - These are removable and mostly caused by our program.
  2. Error: - These are non-recoverable and mostly caused due to lack of system resources.  






Checked Vs. Unchecked Exceptions: -

Checked Exceptions:-
                 The exceptions which are checked by the compiler for smooth execution of program at runtime are called checked Exceptions.
Example: InterruptedException, FileNotFoundException.
Unchecked Exceptions:-
                    The exceptions which are not checked by the compiler are called unchecked exceptions.
Example:  ArithmeticException, NullPointerException, BompBlastException.
  1. Whether the exception is checked or unchecked, compulsory it should be occurs at run time only.  There is no chance of occurring at compile time.
  2. RuntimeException and its child classes, Errors and its child classes are unchecked and all the remaining are considered as Checked Exceptions.

Fully checked Vs. Partially Checked Exceptions: -

A checked Exception is said be fully checked if and only if, its entire child classes also checked, otherwise that checked exception is called partially checked exception.
Example:
                    Exception    --------   Partially checked
                    IOException -----       Fully checked
                    ArithmeticException ------- Unchecked Exception.