Exception  in the unwanted unexpected event that disturbs the normal flow of the program is called an exception.

Example

SleepingException 

TyrePunchuredException 

FileNotFoundException ...etc.

It is highly recommended to handle exceptions. The main objective of exception handling is graceful (normal) termination of the program.

What is the meaning of exception handling?

Exception handling doesn't mean repairing an exception. We have to define alternative ways to continue the rest of the program normally this way of "defining alternative is nothing but exception handling".

Example

Suppose our programming requirement is to read data from remote file locating at London at runtime if London file is not available our program should not be terminated abnormally.

We have to provide a local file to continue the rest of the program normally. This way of defining alternative is nothing but exception handling.

Example:
Try { read data from london file } catch(FileNotFoundException e) { use local file and continue rest of the program normally } } . . .

Runtime stack mechanism

For every thread, JVM will create a separate stack all method calls performed by the thread will be stored in that stack. 

Each entry in the stack is called "one activation record" (or) "stack frame". 

 After completing every method call JVM removes the corresponding entry from the stack. After completing all method calls JVM destroys the empty stack and terminates the program normally.

Example:
class Test { public static void main(String[] args){ doStuff(); } public static void doStuff(){ doMoreStuff(); } public static void doMoreStuff(){ System.out.println("Hello"); }} Output: Hello

 

Default exception handling in java

1) If an exception raised inside any method then the method is responsible to create an Exception object with the following information. 

2) Name of the exception. 

3) Description of the exception.

 4) Location of the exception. (StackTrace) After creating that Exception object the method handovers that object to the JVM. JVM checks whether the method contains any exception handling code or not. 

5) If the method won't contain any handling code then JVM terminates that method abnormally and removes corresponding entry form the stack.

6)  JVM identifies the caller method and checks whether the caller method contains any handling code or not. If the caller method also does not contain handling code then JVM terminates that caller also abnormally and the removes corresponding entry from the stack. 

7) This process will be continued until the main() method and if the main() method also doesn't contain any exception handling code then JVM terminates main() method and removes the corresponding entry from the stack.

 8) Then JVM handovers the responsibility of exception handling to the default exception handler. 

9) The default exception handler just prints exception information to the console in the following formats and terminates the program abnormally. Name of exception: description Location of exception (stack trace)

Example:
class Test { public static void main(String[] args){ doStuff(); } public static void doStuff(){ doMoreStuff(); } public static void doMoreStuff(){ System.out.println(10/0); }} Output: Runtime error Exception in thread "main" java.lang.ArithmeticException: / by zero at Test.doMoreStuff(Test.java:10) at Test.doStuff(Test.java:7) at Test.main(Test.java:4)

Diagram



Exception hierarchy


Throwable acts as a root for exception hierarchy. The throwable class contains the following two child classes.


Exception: Most of the cases exceptions are caused by our program and these are recoverable. Ex: If FileNotFoundException occurs we can use a local file and we can continue the rest of the program execution normally. 

Error: Most of the cases errors are not caused by our program these are due to lack of system resources and these are non-recoverable. Ex: If OutOfMemoryError occurs being a programmer we can't do anything the program will be terminated abnormally. System Admin or Server Admin is responsible to raise/increase heap memory.


Checked Vs Unchecked Exceptions

There are 2 types of exception:

  • Checked : The exceptions which are checked by the compiler for smooth execution of the program at runtime are called checked exceptions.
  • 1)HallTicketMissingException
  • 2)PenNotWorkingException
  • 3)FileNotFoundException
  • Un Checked: The exceptions which are not checked by the compiler are called unchecked exceptions.
  • 1)BombBlaustException
  • 2)ArithmeticException
  • 3)NullPointerException.

Note: RuntimeException and its child classes, Error, and its child classes are unchecked and all the remaining are considered as checked exceptions. Note: Whether exception is checked or unchecked compulsory it should occur at runtime only there is no chance of occurring any exception at compile time.

Partially checked Vs fully checked :

A checked exception is said to be fully checked if and only if all its child classes are also checked. Example: 

1) IOException 

2) InterruptedException

A checked exception is said to be partially checked if and only if some of its child classes are unchecked. Example: Exception The only partially checked exceptions available in java are : 

1) Throwable.

 2) Exception.

Which of the following are checked?

  • RuntimeException-----unchecked
  • Error-----unchecked
  • IOException-----fully checked
  • Exception-----partially checked
  • InterruptedException-----fully checked
  • Throwable------partially checked
  • ArithmeticException ----- unchecked Checked
  • NullPointerException ------ unchecked
  • FileNotFoundException ----- fully checked


Diagram:

Customized exception handling by try-catch

1) It is highly recommended to handle exceptions. 

2) In our program the code which may cause an exception is called risky code, we have to place risky code inside try block and the corresponding handling code inside the catch block.

Example:

Try
{
risky code
}
catch(Exception e)
{
handling code
}

Without try-catch

Example:
class Test { public static void main(String[] args){ System.out.println("statement1"); System.out.println(10/0); System.out.println("statement3"); } } output: statement1 RE:AE:/by zero at Test.main() Abnormal termination

With try-catch

Example:
class Test { public static void main(String[] args){ System.out.println("statement1"); try{ System.out.println(10/0); } catch(ArithmeticException e){ System.out.println(10/2); } System.out.println("statement3"); }} Output: statement1 5 statement3 Normal termination.

Control flow in try-catch

try{
statement1;
statement2;
statement3;
}
catch(X e) {
statement4;
}
statement5;

Output: statement1 5 statement3 Normal termination.  
.
.
.
  • Case 1:   There is no exception. 1, 2, 3, 5 normal terminations.
  • Case 2:  if an exception raised at statement 2 and corresponding catch block matched 1, 4, 5 normal terminations.
  • Case 3:  if an exception raised at statement 2 but the corresponding catch block not matched, 1 followed by abnormal termination.
  • Case 4: if an exception raised at statement 4 or statement 5 then it's always abnormal termination of the program.

Note: 1) Within the try block if anywhere an exception raised then the rest of the try block won't be executed even though we handled that exception. Hence we have to place/take only risk code inside try and length of the try block should be as less as possible. 2) If any statement raises an exception and it is not part of any try block then it is always abnormal termination of the program. 3) There may be a chance of raising an exception inside catch and finally blocks also in addition to try block.

Various methods to print exception information:

The Throwable class defines the following methods to print exception information to the console. printStackTrace()
This method prints exception information in the following format. Name of the exception: description of the exception Stack trace
toString():
This method prints exception information in the following format. Name of the exception: description of the exception
getMessage():
This method returns only a description of the exception. Description.


Example: Note: Default exception handler internally uses the printStackTrace() method to print exception information to the console.

Try with multiple catch blocks

The way of handling an exception is varied from exception to exception hence for every exception raise a separate catch block is required .i.e try with multiple catch blocks is possible and recommended to use.


Example: This approach is not recommended because for any type of Exception we are using the same catch block.

try
{ . . . . } catch(Exception e) { default handler }

This approach is highly recommended because for any exception raise we are defining a separate catch block.

try
{ . . . . catch(FileNotFoundException e) { use local file } catch(ArithmeticException e) { perform these Arithmetic operations } catch(SQLException e) { don't use oracle db, use mysql db } catch(Exception e) { default handler }


If try with multiple catch blocks presents then the order of catch blocks is very important it should be from child to parent by mistake if we are taking from parent to child then we will get Compile time error saying "exception xxx has already been caught".

class Test
{ public static void main(String[] args) { try { System.out.println(10/0); } catch(Exception e) { e.printStackTrace(); } catch(ArithmeticException e) { e.printStackTrace(); }}} Output: Compile time error. Test.java:13: exception java.lang.ArithmeticException has already been caught catch(ArithmeticException e)

class Test
{ public static void main(String[] args) { try { System.out.println(10/0); } catch(ArithmeticException e) { e.printStackTrace(); } catch(Exception e) { e.printStackTrace(); }}} Output: Compile successfully.

Finally block

  • It is never recommended to take clean up code inside try block because there is no guarantee for the execution of every statement inside a try.
  • It is never recommended to place clean up code inside the catch block because if there is no exception then catch block won't be executed.
  • We require someplace to maintain clean up code which should be executed always irrespective of whether exception raised or not raised and whether handled or not handled such type of place is nothing but finally block.
  • Hence the main objective of finally block is to maintain cleanup code.
Example:
Try { risky code } catch(x e) { handling code } finally { cleanup code }

The specialty of finally block is it will be executed always irrespective of whether the exception raised or not raised and whether handled or not handled.


Example 1: class Test { public static void main(String[] args) { try { System.out.println("try block executed"); } catch(ArithmeticException e) { System.out.println("catch block executed"); } finally { System.out.println("finally block executed"); }}} Output: Try block executed Finally block executed

Example 2: class Test { public static void main(String[] args) { try { System.out.println("try block executed"); System.out.println(10/0); } catch(ArithmeticException e) { System.out.println("catch block executed"); } finally { System.out.println("finally block executed"); }}} Output: Try block executed Catch block executed Finally block executed
Example 3:
class Test { public static void main(String[] args) { try { System.out.println("try block executed"); System.out.println(10/0); } catch(NullPointerException e) { System.out.println("catch block executed"); } finally { System.out.println("finally block executed"); }}} Output: Try block executed Finally block executed Exception in thread "main" java.lang.ArithmeticException: / by zero at Test.main(Test.java:8)

Return Vs Finally

Even though return present in try or catch blocks first finally will be executed and after that only return statement will be considered that is finally block dominates return statement.

Example:
class Test { public static void main(String[] args) { try { System.out.println("try block executed"); return; } catch(ArithmeticException e) { System.out.println("catch block executed"); } finally { System.out.println("finally block executed"); }}} Output: Try block executed Finally block executed

If the return statement presents try-catch and finally blocks then finally block return statement will be considered.

class Test
{
public static void main(String[] args)
{
System.out.println(methodOne());
}
public static int methodOne(){
try
{
System.out.println(10/0);
return 777;
}
catch(ArithmeticException e)
{
return 888;
}
finally{
return 999;
}}}
Output:
999
 

There is only one situation where the finally block won't be executed is whenever we are using System.exit(0) method. Then JVM itself will be shut down, in this case finally block won't be executed. i.e., System.exit(0); dominates finally block.

try
Example: class Test { public static void main(String[] args) { try { System.out.println("try"); System.exit(0); } catch(ArithmeticException e) { System.out.println("catch block executed"); } finally { System.out.println("finally block executed"); }}} Output: Try

Note : System.exit(0); instead of zero, we can take any integer value zero means normal termination, non-zero means abnormal termination this status code internally used by JVM, whether it is zero or non-zero there is no change in the result and effect is same

Difference between final, finally, and finalize

Final

  • The Final is the modifier applicable for class, methods, and variables.
  • If a class declared as the final then child class creation is not possible.
  • If a method declared as the final then overriding of that method is not possible.
  • If a variable declared as the final then reassignment is not possible.

Finally

It is the block always associated with try-catch to maintain clean up code which should be executed always irrespective of whether exception raised or not raised and whether handled or not handled.

Finalize

It is a method which should be called by garbage collector always just before destroying an object to perform cleanup activities.

Note: To maintain clean up code faunally block is recommended over the finalize() method because we can't expect the exact behavior of GC.

Control flow in try-catch-finally

class Test
{
public static void main(String[] args){
try{
System.out.println("statement1");
System.out.println("statement2");
System.out.println("statement3");
}
catch(Exception e){
System.out.println("statement4");
}
finally
{
System.out.println("statement5");
}
System.out.println("statement6");
}
}
 
  • Case 1: If there is no exception. 1, 2, 3, 5, 6 normal termination.
  • Case 2: if an exception raised at statement 2 and corresponding catch block matched. 1,4,5,6 normal terminations.
  • Case 3: if an exception raised at statement 2 and the corresponding catch block is not matched. 1,5 abnormal termination.
  • Case 4: if an exception raised at statement 4 then it's always abnormal termination but before the finally block will be executed.
  • Case 5: if an exception raised at statement 5 or statement 6 its always abnormal termination.

Control flow in nested try-catch-finally


class Test { public static void main(String[] args){ try{ System.out.println("statement1"); System.out.println("statement2"); System.out.println("statement3"); try{ System.out.println("statement4"); System.out.println("statement5"); System.out.println("statement6"); } catch(ArithmeticException e){ System.out.println("statement7"); } finally { System.out.println("statement8"); } System.out.println("statement9"); } catch(Exception e) { System.out.println("statement10"); } finally { System.out.println("statement11"); } System.out.println("statement12"); } }
  • Case 1: if there is no exception. 1, 2, 3, 4, 5, 6, 8, 9, 11, 12 normal termination.
  • Case 2: if an exception raised at statement 2 and corresponding catch block matched 1,10,11,12 normal terminations.
  • Case 3: if an exception raised at statement 2 and the corresponding catch block is not matched 1, 11 abnormal termination.
  • Case 4: if an exception raised at statement 5 and corresponding inner catch has matched 1, 2, 3, 4, 7, 8, 9, 11, 12 normal terminations.
  • Case 5: if an exception raised at statement 5 and inner catch has not matched but the outer catch block has matched. 1, 2, 3, 4, 8, 10, 11, 12 normal termination.
  • Case 6: if an exception raised at statement 5 and both inner and outer catch blocks are not matched. 1, 2, 3, 4, 8, 11 abnormal termination.
  • Case 7: if an exception raised at statement 7 and the corresponding catch block matched 1, 2, 3, 4, 5, 6, 8, 10, 11, 12 normal terminations.
  • Case 8: if an exception raised at statement 7 and the corresponding catch block not matched 1, 2, 3, 4, 5, 6, 8, 11 abnormal terminations.
  • Case 9: if an exception raised at statement 8 and the corresponding catch block has matched 1, 2, 3, 4, 5, 6, 7, 10, 11,12 normal termination.
  • Case 10: if an exception raised at statement 8 and the corresponding catch block not matched 1, 2, 3, 4, 5, 6, 7, 11 abnormal terminations.
  • Case 11: if an exception raised at statement 9 and corresponding catch block matched 1, 2, 3, 4, 5, 6, 7, 8,10,11,12 normal termination.
  • Case 12: if an exception raised at statement 9 and corresponding catch block not matched 1, 2, 3, 4, 5, 6, 7, 8, 11 abnormal terminations.
  • Case 13: if an exception raised at statement 10 is always abnormal termination but before that finally block 11 will be executed.
  • Case 14: if an exception raised at statement 11 or 12 is always abnormal termination.

Note: if we are not entering into the try block then the finally block won't be executed. Once we entered into the try block without executing finally block we can't come out. We can take try-catch inside try i.e., nested try-catch is possible The most specific exceptions can be handled by using inner try-catch and generalized exceptions can be handle by using outer try-catch.

class Test
{
public static void main(String[] args){
try{
System.out.println(10/0);
}
catch(ArithmeticException e)
{
System.out.println(10/0);
}
finally{
String s=null;
System.out.println(s.length());
}}}

output :
RE:NullPointerException

Note: Default exception handler can handle only one exception at a time and that is the most recently raised exception.

Various possible combinations of try-catch-finally

1) Whenever we are writing try block compulsory we should write either catch or finally. i.e., try without a catch or finally is invalid. 

2) Whenever we are writing catch block compulsory we should write a try. i.e., catch without try is invalid. 

3) Whenever we are writing finally block compulsory we should write a try. i.e., finally without try is invalid. 

4) In try-catch-finally order is important. 

5) Within the try-catch-finally blocks, we can take try-catch-finally. i.e., nesting of try-catch-finally is possible. 6) For try-catch-finally blocks curly braces are mandatory.

class Test1 {
public static void main(String[] args){ try {} catch(ArithmeticException e) {} }} Output: Compile and running successfully.
class Test2 {
public static void main(String[] args){ try {} catch(ArithmeticException e) {} catch(NullPointerException e) {} } } Output: Compile and running successfully.
class Test3 {
public static void main(String[] args){ try {} catch(ArithmeticException e) {} catch(ArithmeticException e) {} } } Output: Compile time error. Test1.java:7: exception java.lang.ArithmeticException has already been caught catch(ArithmeticException e)
class Test4 {
public static void main(String[] args){ try {} } } Output: Compile time error Test1.java:3: 'try' without 'catch' or 'finally' try
class Test5 {
public static void main(String[] args){ catch(Exception e) {} } } Output: Compile time error. Test1.java:3: 'catch' without 'try' catch(Exception e)
class Test6 {
public static void main(String[] args){ try {} System.out.println("hello"); catch(Exception e) {} } } Output: Compile time error. Test1.java:3: 'try' without 'catch' or 'finally' Try
class Test7 {
public static void main(String[] args){ try {} catch(Exception e) {} finally {} } } Output: Compile and running successfully.
class Test8 {
public static void main(String[] args){ try {} finally {} } } Output: Compile and running successfully.
class Test9 {
public static void main(String[] args){ try {} finally {} finally {} } } Output: Compile time error. Test1.java:7: 'finally' without 'try' Finally
class Test10 {
public static void main(String[] args){ try {} catch(Exception e) {} System.out.println("hello"); finally {} } } Output: Compile time error. Test1.java:8: 'finally' without 'try' Finally
class Test11 {
public static void main(String[] args){ try {} finally {} catch(Exception e) {} } } Output: Compile time error. Test1.java:7: 'catch' without 'try' catch(Exception e)
class Test12 {
public static void main(String[] args){ finally {} } } Output: Test1.java:3: 'finally' without 'try' Finally
class Test13 {
public static void main(String[] args){ try { try{} catch(Exception e){} } catch(Exception e) {} } } Output: Compile and running successfully.
class Test14 {
public static void main(String[] args){ try { } catch(Exception e) { try{} finally{} } } } Output: Compile and running successfully.
class Test15 {
public static void main(String[] args){ try { } catch(Exception e) { try{} catch(Exception e){} } finally{ finally{} } } } Output: Compile time error. Test1.java:11: 'finally' without 'try' finally{}
class Test16 {
public static void main(String[] args){ finally{} try{ } catch(Exception e){} } } Output: Compile time error. Test1.java:3: 'finally' without 'try' finally{}
class Test17 {
public static void main(String[] args){ try{ } catch(Exception e){} finally { try{} catch(Exception e){} finally{} } } } Output: Compile and running successfully.

Throw statement

Sometimes we can create an Exception object explicitly and we can hand over to the JVM manually by using the throw keyword.

The result of the following 2 programs is exactly the same.

class Test
{ public static void main(String[] args){ System.out.println(10/0); }}

In this case creation of ArithmeticException object and handover to the JVM will be performed automatically by the main() method.

class Test
{ public static void main(String[] args){ System.out.println(10/0); }}

In this case, we are creating an exception objects explicitly and handover to the JVM manually.

Note: In general we can use throw keyword for customized exceptions but not for predefined exceptions. Case 1: throw e; If e refers null then we will get NullPointerException.

class Test1
{ static ArithmeticException e=new ArithmeticException(); public static void main(String[] args){ throw e; } } Output: Runtime exception: Exception in thread "main" java.lang.ArithmeticException . . .
class Test2
{ static ArithmeticException e; public static void main(String[] args){ throw e; } } Output: Exception in thread "main" java.lang.NullPointerException at Test3.main(Test3.java:5)

Case 2: After throw statement we can't take any statement directly otherwise we will get a compile-time error saying an unreachable statement. Example:

class Test1
{ public static void main(String[] args){ System.out.println(10/0); System.out.println("hello"); } } Output: Runtime error: Exception in thread "main" java.lang.ArithmeticException: / by zero at Test3.main(Test3.java:4)

Case 3: We can use throw keyword only for Throwable types otherwise we will get a compile-time error saying incomputable types. Example:

class Test1
{ public static void main(String[] args){ throw new Test3(); } }Output: Compile time error. Test3.java:4: incompatible types found : Test3 required: java.lang.Throwable throw new Test3();
class Test2 extends RuntimeException
{ public static void main(String[] args){ throw new Test3(); } } Output: Runtime error: Exception in thread "main" Test3 at Test3.main(Test3.java:4)

Throws statement

In our program, if there is any chance of raising checked exception compulsory we should handle either by try-catch or by throws keyword otherwise the code won't compile.

import java.io.*;
class Test3 { public static void main(String[] args){ PrinterWriter out=new PrintWriter("abc.txt"); out.println("hello"); } } CE : Unreported exception java.io.FileNotFoundException; must be caught or declared to be thrown.
class Test3
{ public static void main(String[] args){ Thread.sleep(5000); } } Unreported exception java.lang.InterruptedException; must be caught or declared to be thrown.

We can handle this compile-time error by using the following 2 ways. Example:

By using try-catch

class Test3
{ public static void main(String[] args){ try { Thread.sleep(5000); } catch(InterruptedException e){} } } Output: Compile and running successfully

By using throws keyword We can use throws keyword to delicate the responsibility of exception handling to the caller method. Then the caller method is responsible to handle that exception.

class Test3
{ public static void main(String[] args)throws InterruptedException{ Thread.sleep(5000); } } Output: Compile and running successfully
    Note :
  • Hence the main objective of the "throws" keyword is to delicate the responsibility of exception handling to the caller method.
  • "throws" keyword required only checked exceptions. Usage of throws for unchecked exceptions there is no use.
  • "throws" keyword required only to convenes complier. The usage of throws keyword doesn't prevent abnormal termination of the program.
  • Hence recommended to use try-catch over throws keyword.

class Test { public static void main(String[] args)throws InterruptedException{ doStuff(); } public static void doStuff()throws InterruptedException{ doMoreStuff(); } public static void doMoreStuff()throws InterruptedException{ Thread.sleep(5000); } } Output: Compile and running successfully.

In the above program if we are removing at least one throws keyword then the program won't compile. 

Case 1: we can use throws keyword only for Throwable types otherwise we will get a compile-time error saying incompatible types.

class Test3{
public static void main(String[] args) throws Test3 {} } Output: Compile time error Test3.java:2: incompatible types found : Test3 required: java.lang.Throwable public static void main(String[] args) throws Test3 . .
class Test3 extends RuntimeException{
public static void main(String[] args) throws Test3 {} } Output: Compile and running successfully.

Case 2: Example:

class Test3{
public static void main(String[] args){ throw new Exception(); } } Output: Compile time error. Test3.java:3: unreported exception java.lang.Exception; must be caught or declared to be thrown
class Test3{
public static void main(String[] args){ throw new Error(); } } Output: Runtime error Exception in thread "main" java.lang.Error at Test3.main(Test3.java:3)

Case 3: In our program within the try block, if there is no chance of raising an exception then we can't right catch block for that exception otherwise we will get a compile-time error saying exception XXX is never thrown in body of corresponding try statement. But this rule is applicable only for fully checked exceptions.

image7 image8

Case 4: We can use throws keyword only for constructors and methods but not for classes. execp9:img

Exception handling keywords summary

1) try: To maintain risky code. 2) catch: To maintain handling code. 3) finally: To maintain cleanup code. 4) throw: To handover our created exception object to the JVM manually. 5) throws: To delegate the responsibility of exception handling to the caller method.

Various possible compile-time errors in exception handling

1) Exception XXX has already been caught. 

2) Unreported exception XXX must be caught or declared to be thrown. 

3) Exception XXX is never thrown in body of corresponding try statement.

 4) Try without a catch or finally.

 5) Catch without a try. 

6) Finally without a try. Incompatible types. Found: test Requried:java.lang.Throwable; 7) Unreachable statement.

Customized Exceptions (User-defined Exceptions)

Sometimes we can create our own exception to meet our programming requirements. Such types of exceptions are called customized exceptions (user-defined exceptions). Example: 1) InSufficientFundsException 2) TooYoungException 3) TooOldException


class TooYoungException extends RuntimeException { TooYoungException(String s) { super(s); } } class TooOldException extends RuntimeException { TooOldException(String s) { super(s); } } class CustomizedExceptionDemo { public static void main(String[] args){ int age=Integer.parseInt(args[0]); if(age>60) { throw new TooYoungException("please wait some more time.... u will get best match"); } else if(age<18 1="" age="" already="" by="" chance="" crossed....no="" details="" e-mail="" else="" get="" getting="" married="" match="" new="" of="" output:="" r="" scjp="" soon="" system.out.println="" throw="" toooldexception="" u="" will="" you="">java CustomizedExceptionDemo 61 Exception in thread "main" TooYoungException: please wait some more time.... u will get best match at CustomizedExceptionDemo.main(CustomizedExceptionDemo.java:21) 2)E:\scjp>java CustomizedExceptionDemo 27 You will get match details soon by e-mail 3)E:\scjp>java CustomizedExceptionDemo 9 Exception in thread "main" TooOldException: u r age already crossed....no chance of getting married at CustomizedExceptionDemo.main(CustomizedExceptionDemo.java:25)

Note: It is highly recommended to maintain our customized exceptions as unchecked by extending RuntimeException. We can catch any Throwable type including Errors also. Example:

try {
} catch(){ } //Valid

Top-10 Exceptions

Exceptions are divided into two types. They are: 

1) JVM Exceptions:

 2) Programmatic exceptions:

JVM Exceptions

The exceptions are raised automatically by the JVM whenever a particular event occurs. 

Example: 

 1) ArrayIndexOutOfBoundsException(AIOOBE) 

2) NullPointerException (NPE).

Programmatic Exceptions

The exceptions which are raised explicitly by the programmer (or) by the API developer are called programmatic exceptions. Example: 1) IllegalArgumentException(IAE).

Top 10 Exceptions 

1) ArrayIndexOutOfBoundsException: It is the child class of RuntimeException and hence it is unchecked. Raised automatically by the JVM whenever we are trying to access array element with out of range index. Example:

class Test{
public static void main(String[] args){ int[] x=new int[10]; System.out.println(x[0]);//valid System.out.println(x[100]);//ArrayIndexOutOfBoundsException System.out.println(x[-100]);//ArrayIndexOutOfBoundsException } }

2) NullPointerException: It is the child class of RuntimeException and hence it is unchecked. Raised automatically by the JVM, whenever we are trying to call any method on null.

class Test{
public static void main(String[] args){
String s=null;
System.out.println(s.length()); //R.E: NullPointerException
}
}

3) StackOverFlowError : It is the child class of Error and hence it is unchecked. Whenever we are trying to invoke the recursive method call JVM will raise StackOverFloeError automatically.

class Test
{ public static void methodOne() { methodTwo(); } public static void methodTwo() { methodOne(); } public static void main(String[] args) { methodOne(); } } Output: Run time error: StackOverFloeError

4) NoClassDefFound: It is the child class of Error and hence it is unchecked. JVM will raise this error automatically whenever it is unable to find the required .class file. Example: java Test If Test.class is not available. Then we will get a NoClassDefFound error.

5) ClassCastException: It is the child class of RuntimeException and hence it is unchecked. Raised automatically by the JVM whenever we are trying to typecast parent object to child type. Example:


  

6) ExceptionInInitializerError: It is the child class of Error and it is unchecked. Raised automatically by the JVM, if any exception occurs while performing static variable initialization and static block execution.


class Test{ static int i=10/0; } Output: Runtime exception: Exception in thread "main" java.lang.ExceptionInInitializerError . .

class Test{ static { String s=null; System.out.println(s.length()); }} Output: Runtime exception: Exception in thread "main" java.lang.ExceptionInInitializerError

7) IllegalArgumentException: It is the child class of RuntimeException and hence it is unchecked. Raised explicitly by the programmer (or) by the API developer to indicate that a method has been invoked with inappropriate argument.


class Test{ public static void main(String[] args){ Thread t=new Thread(); t.setPriority(10);//valid t.setPriority(100);//invalid }} Output: Runtime exception Exception in thread "main" java.lang.IllegalArgumentException.

8) NumberFormatException: It is the child class of IllegalArgumentException and hence is unchecked. Raised explicitly by the programmer or by the API developer to indicate that we are attempting to convert string to the number. But the string is not properly formatted.


class Test{ public static void main(String[] args){ int i=Integer.parseInt("10"); int j=Integer.parseInt("ten"); }} Output: Runtime Exception Exception in thread "main" java.lang.NumberFormatException: For input string: "ten"

9) IllegalStateException: It is the child class of RuntimeException and hence it is unchecked. Raised explicitly by the programmer or by the API developer to indicate that a method has been invoked at an inappropriate time. Example: Once the session expires we can't call any method on the session object otherwise we will get IllegalStateException

HttpSession session=req.getSession();
System.out.println(session.getId()); session.invalidate(); System.out.println(session.getId()); // IllgalstateException

10) AssertionError: It is the child class of Error and hence it is unchecked. Raised explicitly by the programmer or by API developer to indicate that the Assert statement fails. Example: assert(false);

Exception/Error Raised automatically by JVM(JVM Exceptions) 1) AIOOBE 2) NPE(NullPointerException) 3) StackOverFlowError 4) NoClassDefFoundError 5) CCE(ClassCastException) 6) ExceptionInInitializerError

Exception/Error Raised explicitly either by the programmer or by API developer (Programmatic Exceptions). 1) IAE(IllegalArgumentException) 2) NumberFormatException 3) IllegalStateException 4) AssertionError

1.7 Version Enhancements 

As part of 1.7 version enhancements in Exception Handling the following 2 concepts introduced try with resources multi-catch block try with resources Until 1.5 version it is highly recommended to write finally block to close all resources which are open as part of the try block.

BufferedReader br=null;
try{ br=new BufferedReader(new FileReader("abc.txt")); //use br based on our requirements } catch(IOException e) { // handling code } finally { if(br != null) br.close(); }

problems in this approach 

1) Compulsory programmer is required to close all opened resources which increases the complexity of the programming 

2) Compulsory we should write finally block explicitly which increases the length of the code and reviews readability. To overcome these problems Sun People introduced "try with resources" in 1.7 versions.

The main advantage of "try with resources" is

the resources which are opened as part of try block will be closed automatically Once the control reaches the end of the try block either normally or abnormally and hence we are not required to close explicitly due to the complexity of programming will be reduced, it is not required to write finally block explicitly and hence the length of the code will be reduced and readability will be improved.

try(BufferedReader br=new BufferedReader(new FileReader("abc.txt")))
{ use be based on our requirement, br will be closed automatically , Onec control reaches end of try either normally or abnormally and we are not required to close explicitly } catch(IOException e) { // handling code }

We can declare any no of resources but all these resources should be separated with ;(semicolon)

try(R1 ; R2 ; R3)
{ ------------- ------------- }

All resources should be auto closable resources, a resource is said to be auto closable if and only if the corresponding class implements the java.lang.AutoClosable interface either directly or indirectly. All resource reference variables are implicitly final and hence we can't perform reassignment within the try block.

try(BufferedReader br=new BufferedReader(new FileReader("abc.txt"))) ;
{ br=new BufferedReader(new FileReader("abc.txt")); } output : CE : Can't reassign a value to final variable br . .

Until 1.6 version try should be followed by either catch or finally but 1.7 version we can take only try with the resource without a catch or finally

try(R)
{ //valid } . .

The main advantage of "try with resources" finally block will become dummy because we are not required to close resources explicitly.

Multi catch block 

Even though Multiple Exceptions having same handling code we have to write a separate catch block for every exception, it increases the length of the code and reviews readability

try{
----------------- ----------------- } catch(ArithmeticException e) { e.printStackTrace(); } catch(NullPointerException e) { e.printStackTrace(); } catch(ClassCastException e) { System.out.println(e.getMessage()); } catch(IOException e) { System.out.println(e.getMessage()); }

To overcome this problem Sun People introduced the "Multi catch block" concept in 1.7 version. The main advantage of the multi-catch block is we can write a single catch block, which can handle multiple different exceptions

try{
----------------- ----------------- } catch(ArithmeticException | NullPointerException e) { e.printStackTrace(); } catch(ClassCastException | IOException e) { System.out.println(e.getMessage()); }

In multi-catch block, there should not be any relation between Exception types(either child to parent Or parent to child Or same type, otherwise we will get Compile time error ) Example:

try{
----------------- ----------------- } catch(ArithmeticException | Exception e) { // compile time error e.printStackTrace();//invalid }

Exception Propagation 

Within a method if an exception raised and if that method doesn't handle that exception then the Exception object will be propagated to the caller then the caller method is responsible to handle those exceptions. This process is called Exception Propagation.

Rethrowing an Exception 

To convert the one exception type to another exception type, we can use the rethrowing exception concept.

class Test
{ public static void main(String[] args){ try { System.out.println(10/0); } catch(ArithmeticException e) { throw new NullPointerException(); } } } output: RE:NPE