Exception Handling in Java | Part-3

This is the third post on a series of Exception Handling in Java. In this article, we will revise exception handling keywords, various possible compile-time errors, in detail about customized or user-defined exceptions and enhancement. Before starting these, please go through Exception Handling in Java | Part-1 and Exception Handling in Java | Part-2so that you clear with the basics of Exception Handling.



Exception Handling keyword summary :


  1. try: To maintain risky code

  2. catch: to maintain exception handling code

  3. finally: to maintain cleanup code

  4. throw: to handover created an exception object to the JVM manually

  5. throws: to delegate the responsibility of exception handling to the caller


Various possible compile-time exceptions :


  • Unreported exception XYZ must be caught or declared to be thrown

  • Exception XYZ has already be caught

  • Exception XYZ is never thrown in body of corresponding try statement

  • Unreachable statement

  • Incompatible types - Found: XYZ required: Throwable

  • try without a catch or finally

  • catch without try

  • finally without try


Customized or User-defined exceptions :


Sometimes we need to define our own exception to meet the programming requirement, such type of exceptions are called user-defined exceptions.

Note :

  1. The throw keyword is best suitable for user-defined exceptions

  2. The custom exception should extend RuntimeException if you want to make it unchecked else extend it with Exception.

  3. Checked – Extends java.lang.Exception, need to handle it explicitly

  4. class MyException extends Exception {
        MyException(String s) {
            super(s);
        }
    }
    
    public class Test1 {
        public static void main(String[] args) {
            int demoninator = 0;
            if (demoninator == 0) {
                try {
                    throw new MyException("Denominator as 0 is not allowed");
                } catch (MyException e) {
                    System.out.println(e);
                }
            } else {
                System.out.println(25 / demoninator);
            }
        }
    }
    
    o/p:
    ExceptionHandling.MyException: Denominator as 0 is not allowed
      
  5. Unchecked – Extends java.lang.RuntimeException no need handle. Be careful while throwing RuntimeException.

  6. class MyException1 extends RuntimeException {
        MyException1(String s) {
            super(s);
        }
    }
    
    public class Test {
        public static void main(String[] args) {
            int demoninator = 0;
            if (demoninator == 0) {
                throw new MyException1("Denominator as 0 is not allowed");
            }
        }
    }
    
    o/p:
    Exception in thread "main" ExceptionHandling.MyException1: Denominator as 0 is not allowed
    	at ExceptionHandling.Test.main(Test.java:11)
      

Top 10 exceptions :


Based on the person who is raising an exception all exceptions are divided into two parts:

JVM Exceptions :

Exceptions which are raised automatically by JVM whenever a particular event occurs are called JVM exceptions
For e.g. ArithmeticException, NullPointerException

Programmatic Exceptions :

The exceptions which are raised explicitly either by the programmer or by API developer to indicate that something goes wrong are called programmatic exceptions.

    Raised by JVM:
  1. ArrayIndexOutOfBoundsException

  2. NullPointerException

  3. ClassCastException

  4. StackOverflowError

  5. ClassNotFoundException

  6. ExceptionInInitializerError

  7. Raised by programmer or API developer:
  8. IllegalArgumentException

  9. NumberFormatException

  10. IllegalThreadStateException

  11. AssertionError

Try with resources :


Until Java 1.6 it is highly recommended to write finally block to close the resources which are open as a part of the try block. In Java 1.7 introduced a new concept try with the resource.

The problem with the old approach is
- It's mandatory for a programmer to close resources used in try block using finally block.
- It increases the complexity of a program, length of code, and reduces readability.

The main advantage of try with resources is whatever resources we open as a part of the try block will be closed automatically once control reaches the end of the try block.

try with finally :

public class FNFExceptionDemo {
    public static void main(String[] args) {
        BufferedReader br = null;
        try{
            br = new BufferedReader(new FileReader("abc.txt"));
            br.read();
        }catch (FileNotFoundException f){
            System.out.println("Use local file.");
        }finally {
            if (br!=null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

output

java.io.FileNotFoundException: abc.txt (No such file or directory)
	at java.io.FileInputStream.open0(Native Method)
	at java.io.FileInputStream.open(FileInputStream.java:195)
	at java.io.FileInputStream.(FileInputStream.java:138)
	at java.io.FileInputStream.(FileInputStream.java:93)
	at java.io.FileReader.(FileReader.java:58)
	at ExceptionHandling.FNFExceptionDemo.main(FNFExceptionDemo.java:8)

try without finally :

public class FNFExceptionDemo {
    public static void main(String[] args) {
        try(BufferedReader br = new BufferedReader(new FileReader("abc.txt"))){
            br.read();
        } catch (IOException f){
            System.out.println("Use local file.");
        }
    }
}
output

java.io.FileNotFoundException: abc.txt (No such file or directory)
	at java.io.FileInputStream.open0(Native Method)
	at java.io.FileInputStream.open(FileInputStream.java:195)
	at java.io.FileInputStream.(FileInputStream.java:138)
	at java.io.FileInputStream.(FileInputStream.java:93)
	at java.io.FileReader.(FileReader.java:58)
	at ExceptionHandling.FNFExceptionDemo.main(FNFExceptionDemo.java:8)

We can write multiple resources in a try but these resources should be separated with (;)

try(r1;r2;r3){
   //risky code        
}catch (IOException f){
    
}

Note :

  • All resources should be AutoCloseable Resources. The resource is said to be AutoCloseable if and only if the corresponding class implements Interface AutoCloseable

  • All I/O, Database, Network related resources are already implements autoCloseable interface

  • AutoCloseable interface introduced in 1.7 and it has only one method i.e. close()

  • All resource reference variables are implicitly final and hence within the try block, we can't perform reassignment otherwise we will get a compile-time error

  • public class Test1 {
        public static void main(String[] args) {
            try(BufferedReader br = new BufferedReader(new FileReader("abc.txt"))){
                br = new BufferedReader(new FileReader("xyz.txt"));
            } catch (IOException f){
                System.out.println("Use local file.");
            }
        }
    }
    
    o/p:
    Error:(4, 6) java: auto-closeable resource br may not be assigned
    

Until Java 1.6, try should be associated with either catch or finally. But from Java 1.7 onwards we can take only try with resources and without catch/finally

try(r1;r2;r3){
   //risky code r1,r2,r3 are resources       
}

Multi catch block :


Until Java 1.6 even though multiple different exceptions having the same handling code but for every exception type, we have to write a separate catch block. So it increases the length of the code and reduces the readability of code.
For e.g.

try{

}catch(ArithmeticException e){
	e.printStackTrace();
}catch(NullPointerException e){
	e.printStackTrace();
}catch(InterruptedException e){
	e.printStackTrace();
}

To overcome this problem java introduces new concept multiple catch block in Java 1.7

try{

}catch(ArithmeticException/IOException e){
	e.printStackTrace();
}catch(NullPointerException/InterruptedException e){
	e.getMessage();
}

Re-throwing exception:


We can use this approach to convert one exception to another exception type

try{
	System.out.println(10/0);
}catch(ArithmeticException e){
	throw new NullPointerException();
}

UncaughtExceptionHandler


Method invoked when the given thread terminates due to the given uncaught exception.
Any exception thrown by this method will be ignored by the Java Virtual Machine.

package mt;

public class ThreadUncaughtExceptionHandlerDemo {
    public static void main(String[] args) {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Run method started performing 10/0");
                throw new RuntimeException("Intentional exception thrown");
            }
        });
        t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread t, Throwable e) {
                System.out.println("Runtime exception occured for thread : " + t.getName());
                System.out.println(e);
            }
        });
        t.setName("LocalThread");
        t.start();
    }
}

/*
output -
Run method started performing 10/0
Runtime exception occured for thread : LocalThread
java.lang.RuntimeException: Intentional exception thrown
 */

Lets quick summarise what we learn in this post:

  • Exception handling keyword summary

  • Various possible compile-time exceptions

  • Customized/User-Defined exceptions

  • Top 10 exceptions

  • try with resources

  • Multi catch block

With this, we also came to the end of this article and cover all the exception handling in Java. In the next article, we would start with the MultThreading concept in java. Please let us know your views and opinions in the comment section below. I hope you enjoyed this post. Please stay with us for more posts.
For more details on exception handling please refer Video

0 comments:

Post a Comment