Thursday, July 1, 2021

Exception handling in java

 Introduction

An unexpected event that distracts the normal flow of the program is an exception. the main purpose of exception handling is the graceful termination of the program.

Default exception handling


if an exception is raised then the corresponding method is responsible for exception handling failing which its parent will be responsible hence ultimately JVM needs to terminate the exception causing method if no method does the handling.
eg:
public static void main(String[] args) {
dostuff();
}
private static void dostuff() {
domoreStuff();
}
private static void domoreStuff() {
System.out.println(20/0);
}
error:Exception in thread "main" java.lang.ArithmeticException: / by zero
at Exception.ExceptionPract.domoreStuff(ExceptionPract.java:20)
at Exception.ExceptionPract.dostuff(ExceptionPract.java:16)
at Exception.ExceptionPract.main(ExceptionPract.java:12)

the exception should have been handled at method domorestuff() but it was not handled hence method dostuff() was responsible for not handling the exception and main was responsible as dostuff() method had not handled exception too. hence JVM is responsible for the same as the main method is called by JVM, hence JVM handles the exception despite not being handled explicitly. the above termination is known as abnormal termination(at least 1 method getting terminated abnormally leads to abnormal termination of the program.

difference between exception and error
exception is recoverable whereas errors aren't recoverable.
errors are caused due to external factors mostly eg: out of memory

Difference between checked and unchecked exception ( every exception occurs at runtime only).

Checked Exception: The exception that is checked by the compiler if the programmer is handling or not is checked exception.
eg:
public static void main(String[] args) {
PrintWriter p=new PrintWriter("abc.txt");
p.println("hello");
}
Error: java: unreported exception java.io.FileNotFoundException; must be caught or declared to be thrown

Unchecked exception:  The exception which compiler won't be concerned about during the time of compilation is an unchecked exception. 
eg: arithmetic exception

Error and its child classes are unchecked similarly, runtime exception and its child classes are also the unchecked exceptions.

Fully checked and partially checked exceptions

The exception who is checked whereas some of its child are unchecked are partially checked exception, in java there only 2 partially checked exceptions, i.e. Exception class and Throwable class 

try-catch block in exception

the try-catch block is one way for exception handling 
eg:
public static void main(String[] args) {
try {
System.out.println(10 / 0);
}
catch (ArithmeticException e) {
System.out.println("exception caught");
}
System.out.println("abc");
}
O/P: exception caught 
        abc

case: if an exception is raised in a try block and catch block is matched. ( only risky code is recommended to be kept in try block)
eg: 
try {
System.out.println("abc");
System.out.println(10 / 0);
System.out.println("def");
}
catch (ArithmeticException e) {
System.out.println("exception caught");
}
System.out.println("abc2");
}
O/P: abc
exception caught
abc2

case: if an exception raised inside the catch block.(any statement raising exception outside try block is abnormal termination).
eg:
public static void main(String[] args) {
try {
System.out.println("abc");
System.out.println(10 / 0);
System.out.println("def");
}
catch (ArithmeticException e) {
System.out.println(2/0);
}
System.out.println("abc2");
O/P: abc
Exception in thread "main" java.lang.ArithmeticException: / by zero
at Exception.ExceptionPract.main(ExceptionPract.java:18)

Print Exception information
public static void main(String[] args) {
try {
System.out.println(10/0);
}
catch (ArithmeticException e) {
e.printStackTrace(); // these methods are written in throwable
System.out.println(e.toString());
System.out.println(e.getMessage());
}
System.out.println("abc2");
}
O/P:java.lang.ArithmeticException: / by zero
at Exception.ExceptionPract.main(ExceptionPract.java:13)
java.lang.ArithmeticException: / by zero
/ by zero
abc2

try with multiple catch block

it is always recommended to have multiple catch blocks and different handling codes instead of having a single Exception class
eg1: the catch block is always allocated from top to bottom
try {
System.out.println(10/0);
}
catch (ArithmeticException ae){
System.out.println("first catch "+ae.toString());
}
catch (Exception e) {
System.out.println(e.toString());
}
O/P:first catch java.lang.ArithmeticException: / by zero

eg2: always make sure to have child-to-parent hierarchy.
try {
System.out.println(10/0);
}
catch (Exception ae){
System.out.println(ae.toString());
}
catch (ArithmeticException e) {
System.out.println(e.toString());
}
O/P:Error: java: exception java.lang.ArithmeticException has already been caught.

Note: we cant have 2 catch block for same exceptions.

finally block

some mandatory chunks of code that need to be executed irrespective of exception caught or not are to be written in the finally block.
 case1: no exception caught
try {
System.out.println("inside try block");
}
catch (ArithmeticException e) {
System.out.println("inside catch block");
}
finally {
System.out.println("inside finally block");
}
O/P: inside try block
inside finally block

case2: Exception is caught
try {
System.out.println("inside try block");
int i=10/0;
}
catch (ArithmeticException e) {
System.out.println("inside catch block");
}
finally {
System.out.println("inside finally block");
}
O/P: inside try block
inside catch block
inside finally block

case 3: exception raised not handled -> finally block will be executed before abnormal termination.
try {
System.out.println("inside try block");
int i=10/0;
}
catch (NullPointerException e) {
System.out.println("inside catch block");
}
finally {
System.out.println("inside finally block");
}
O/P: inside try block
inside finally block
Exception in thread "main" java.lang.ArithmeticException: / by zero

case 4: return statement versus finally block: finally block is having higher priority than return statement.
try {
System.out.println("inside try block");
int i=10/0;
return;
}
catch (ArithmeticException e) {
System.out.println("inside catch block");
}
finally {
System.out.println("inside finally block");
}
O/P: inside try block
inside catch block
inside finally block

case 5: if there is a return statement in the try, catch, finally block: finally block has the highest priority
public class ExceptionPract {
public static void main(String[] args) {
System.out.println(m1());
}

private static int m1() {
try {
System.out.println("inside try block");
int i=10/0;
return 555;
}
catch (ArithmeticException e) {
System.out.println("inside catch block");
return 666;
}
finally {
System.out.println("inside finally block");
return 777;
}
}
}
O/P: inside try block
inside catch block
inside finally block
777

case 6: finally versus system.exit(0) : whenever we use system.exit() finally block won't be executed
try {
System.out.println("inside try block");
System.exit(0);
}
catch (ArithmeticException e) {
System.out.println("inside catch block");
}
finally {
System.out.println("inside finally block");
}
O/P: inside try block

control flow - try,catch,finally 

eg:  given the below example answer the different cases
try {
    statement 1
    statement 2
    statement 3 
}
catch (ArithmeticException e) {
    statement 4
}
finally {
    statement 5
}
statement 6

case 1: if there is no exception which of the above statements are executed
statement 1, statement 2,statement 3,statement 5,statement 6 - leads to normal termination

case 2: if there is an exception raised at statement 2 corresponding catch block matched
statement 1,statement 4,statement 5,statement 6 - leads to normal termination

case 3: if there is an exception raised at statement 2 corresponding catch block not matched.
statement 1, statement 5,  leads to abnormal termination as JVM handles the exception.

case 4: if there is an exception raised at statement 4
this leads to abnormal termination but still, the finally block is executed.

case 5: if there is an exception raised at statement 5
leads to abnormal termination as JVM handles the exception.

Nested try-catch-finally

Maintaining try-catch block for specific high-risk code snippets inside the try-catch block so as prevent skipping of the rest of the code. If the inner catch block is not matched then the outer catch block will be taken into consideration. if both won't match then there will be abnormal termination
try {
System.out.println("outer try block");
try
{
System.out.println("inner try block");
System.out.println(10/0);
}
catch (ArithmeticException ae){
System.out.println("inner catch block");
}
System.out.println("outside of inner try-catch block");
}
catch (Exception e) {
System.out.println("outer catch block");
}
finally {
System.out.println("inside finally block");
}
O/P: outer try block
inner try block
inner catch block
outside of inner try-catch block
inside finally block

control flow : try,catch,finally block.
try {
statement 1;
statement 2;
statement 3;
try {
statement 4;
statement 5;
statement 6;
} catch (ArithmeticException ae) {
statement 7;
} finally {
statement 8;
}
statement 9;
}
catch (Exception e) {
statement 10;
}
finally {
statement 11;
}
}
case 1: if there is no exception.
all statements except those of catch block are executed and normal termination is done.

case 2: exception raised at statement -2 and corresponding catch block matched
statement 1, statement 10,statement  11,statement  12 - leads to normal termination

case 3: if exception raised at statement 2 and corresponding catch block not matched.
statement 1,statement 11 - leads to abnormal termination

case 4: if exception raised at statement 5 and corresponding inner catch block matched.
statement 1,statement 2,statement 3,statement 4,statement 7,statement 8,statement 9,statement 11,statement 12 -   leads to normal termination

case 5: if exception raised at statement 5 and inner catch block not matched, but the outer catch block matched.
statement 1,statement 2,statement 3,statement 4,statement 8,statement 10,statement 11,statement 12  - leads to normal termination

case 6: if exception raised at statement 5 and both inner and outer block not matched.
statement 1,statement 2,statement 3,statement 4,statement 8,statement 11 - leads to abnormal termination

case 7: if exception raised at statement 7 and corresponding catch block matched.
statement 1,statement 2,statement 3,statement 4/5/6,statement 8,statement 10,statement 11,statement 12 - leads to normal termination.

case 8: if exception raised at statement 7 and corresponding catch block not matched
statement 1,statement 2,statement 3,statement 4/5/6,statement 8,statement 11 - leads to abnormal termination

case 9: if exception raised at statement 8 and corresponding catch block matched.
statement 1,statement 2,statement 3,statement 4/5/6/7,statement 10,statement 11, statement 12- leads to normal termination.

case 10: if exception raised at statement 8 and corresponding catch not block matched.
statement 1,statement 2,statement 3,statement 4/5/6/7,statement 11- leads to abnormal termination

case 11: if an exception is raised at statement 9 and the corresponding catch block matched.
statement 1,statement 2,statement 3,statement 4/5/6/7,statement 8,statement 10,statement 11 - leads to normal termination.

case 12:  if an exception raised at statement 9 and the corresponding catch block not matched.
statement 1,statement 2,statement 3,statement 4/5/6/7,statement 8,statement 11 - leads to abnormal termination

case 13: if an exception raised at statement 10 
try block statements till the risky code is caught and finally block statement 11 - leads to abnormal termination.

case 14: if an exception raised at statement 11
same as case 13 - leads to abnormal termination

Note: inner finally block is executed only if the inner try block gets a chance to execute.

Various possible combinations of try-catch-finally

1) try { }
    catch(x e) {
    }
    catch(x e) {
    }
O/P : error: exception x has been caught twice with the same kind of exception

2) try { 
         }
O/P: error: try without catch or finally

3)  catch(x e) {
    }
O/P: error: catch without try block

4) finally {
    }
O/P : error: finally without try block

5) try { }
    finally{
    }
    catch(x e) {
    }
O/P : error: catch block should be after try 

6) try { }
     try { }
    catch(x e) {
    }
    finally{
    }
O/P: error: try block without catch

7)  try { }
    catch(x e) {
    }
    finally{
    }
    finally{
    }
O/P: error: finally block without try

8) try { }
    sout("hello");
    catch(x e) {
    }
O/P: error: try should be followed by catch always

9) try { }
    catch(y e){
    }
    sout("hello");
    catch(x e) {
    }
O/P: error: catch without try

10) try { }
    catch(x e) {
    }
    sout("hello");
     finally{
       }
O/P: finally without try

11)  try {
        try{}    
 }
    catch(x e) {
    }
O/P: error: inner try without catch

12)  try sout("try");
    catch(x e) sout("try");
    finally sout("try");
O/P: Error: java: '{' expected

throw keyword

useful to handover our created exception object to the JVM manually.
eg:
public static void main(String[] args) {
throw new ArithmeticException(); //new creation of exception object explicilty
//throw : handover created exception object to JVM manually
}
case 1: if we throw null 
static ArithmeticException ae=new ArithmeticException();
public static void main(String[] args) {
throw ae;
}
O/P:Exception in thread "main" java.lang.ArithmeticException

static ArithmeticException ae;
public static void main(String[] args) {
throw ae;
}
O/P: Exception in thread "main" java.lang.NullPointerException

case2: unreachable statement: after throws statement we cant be able to take any statement.
public static void main(String[] args) {
throw new ArithmeticException();
System.out.println("hello"); // Error: java: unreachable statement
}

case 3: throw keyword can be implemented for only throwable types
public class Throwpract {
public static void main(String[] args) {
throw new Throwpract(); //error : throwpract does not extend Exception class.
}
}
O/P:Error: java: incompatible types: Exception.Throwpract cannot be converted to java.lang.Throwable

public class Throwpract extends RuntimeException{
public static void main(String[] args) {
throw new Throwpract();
}
}
O/P:Exception in thread "main" Exception.Throwpract

throws keyword

whenever there is a possibility of checked exception not handled then the caller takes the responsibility of handling the exception throws is to be used. ultimately JVM will be responsible to handle the exception which in turn will lead to abnormal termination. 
(try-catch is always reccomended to do exception handling whereas throws keyword is always used to convince compiler )

1) we can use throws keyword to delegate the responsibility of exception handling to the caller (JVM or another method)
2) it is required only for checked exceptions and not useful for unchecked exceptions
3) it doesn't serve the purpose, i.e. only convinces the compiler and won't prevent the abnormal termination of the program,

eg1:
public static void main(String[] args) throws InterruptedException {
doStuff();
}
private static void doStuff() throws InterruptedException{
doMoreStuff();
}
private static void doMoreStuff() throws InterruptedException {
Thread.sleep(1000);
}
in the above example the method doMoreStuff() delegeated the exception to doStuff() and doStuff() delegated exception to main(0. hence ultimately it leads to JVM for delegating.

eg2:
only using throws at caller doesnt solve the problem, even the called method should have exception handling in place. all the three in heirarchy should have 
public static void main(String[] args) throws InterruptedException {
doStuff();
}
private static void doStuff() {
doMoreStuff();
}
private static void doMoreStuff() {
Thread.sleep(1000);
}
O/P: Error: java: unreported exception java.lang.InterruptedException; must be caught or declared to be thrown.

Case 1:
public class Throwpract throws Exception {
Throwpract() throws Exception{
}
public void m1() throws Exception{
}
public static void main(String[]args){
}
}
O/P: error: throws cant be used for class

case 2: throws can be used for custom exception too.
public class Throwpract extends Exception {
public static void main(String[]args) throws Throwpract{
}
}

case 3: throw keyword
public static void main(String[]args) {
throw new Exception(); // throw can be preffered for unchecked exception
}
O/P:Error: java: unreported exception java.lang.Exception; must be caught or declared to be thrown.

in the above example error can be used instead of exception.
[Note: if you throw an exception in any method then you must make sure you are throwing unchecked exception only if you throw checked exception then you may need to declare "throws" along with method signature]


case 4: catching checked exception irrespective of try block
try{
System.out.println("hello");
}
catch (IOException e){
}
Error:(14, 5) java: exception java.io.IOException is never thrown in body of the corresponding try statement

the below example runs normally as that is a partially checked/unchecked exception.
try{
System.out.println("hello");
}
catch (Error e){ // even catch(Exception e) runs normal
}

Exception handling keyword summary

1) try :- to maintain risky code we need try block
2) catch ;- to maintain handling code
3) finally :- to maintain clean up code
4) throw :- to handover our created exception object to the jvm manually
5) throws :- to delegate responsibility of exception handling to the caller.

final,finally,finalize()

1) final : it is an access modifiers in java which is applicale for classes , methods and vsriable. nobody can extend final class. if method isfinal we cant override the method.if a variable is final then we cant change its value.

2) finally : is a block associated with try-catch block. finally block is executed irrespective of whether exception is handled or not/ raised or not.

3) finalize : it is associated with garbage collector. one last process to be done before clean-up of a class by GC. just before destroying object garbage collector calls finalize() method.

Customized or user-defined exceptions

the exceptions defined explicitly by the programmer to meet programming requirements are called user-defined exceptions.
eg: in banking applications whenever you withdraw the amount greater than the balance available you need to gracefully warn the user without terminating the transaction hence you use customized exceptions.

eg:
public class Test {
static int balance=2000;
public static void main(String[]args) {
System.out.println("enter the amount to withdraw");
Scanner s = new Scanner(System.in);
int amount = s.nextInt();
if (amount > balance) {
throw new NoEnoughBalanceException("not enough balance");
}
else System.out.println("withdrawn");
}
}
//unchecked exception is extended so as-
//- to compiler wont object about catch
class NoEnoughBalanceException extends RuntimeException{
NoEnoughBalanceException(String msg){
super(msg);
}
}
O/P: enter the amount to withdraw
2222
Exception in thread "main" Exception.NoEnoughBalanceException: not enough balance
at Test.main

Note: Unlike built-in exceptions JVM won't be having any information about custom exception , hence throw keyword is best suited for customized exceptions.

Top 10 exceptions


TRY with resources

whenever we use try block for certain resources like DB connection we may need to close that at the end of the program. hence from the version 1.7 try with resource is introduced which automatically closes on reaching end of the try block
eg:
try (BufferedReader br=new BufferedReader(new FileReader("a.txt"))){
// use br based on our requirement and br is closed automatically
// finally block is not explicitly needed
} catch (Exception e) {
}
Note :
1) we can take any number of resources in try with resource block seperated with semicolon.
2) all the resources should be autocloseable , i.e. all the resource should implement autocloseable interface
3) all resource variables are implicitly final.
4) after 1.7V onwards try without catch block and finally block is valid.
5) from 1.9V version already declared resources can be used without any hassle

multi-catch block

sometimes merging of two catch block in order to reduce code repetition
eg:
try {
System.out.println(10/0);
}
catch (ArithmeticException | NullPointerException e) {
System.out.println(e);
}
Note: in multicatch block there should be no child/parent relation between alternatives.
eg: catch (ArithmeticException | Exception e)  --> is erroneous

re-throwing exception

converting one exception to another type.
try {
System.out.println(10/0);
}
catch (ArithmeticException e) {
throw new NullPointerException();
}



SOLID principles in java

SOLID  Single responsibility principle : a class should have only  reason to change, i.e. a class should have only one responsibility/single...