What is Exception?
It's an event, that occurs during the execution of the program.
It will disrupt your program normal flow.
It creates the Exception Object, which contain information about the Error like
Type of Exception and Message
Stack Trace etc.
Runtime system use this Exception Object and find the class which can handle it.
package learn.Exception;
public class Main {
public static void main(String[] args) {
Main sampleObj = new Main();
sampleObj.method1();
}
private void method1(){
method2();
}
private void method2() {
method3();
}
private void method3() {
int b = 5/0;
}
}
// Output -------
Exception in thread "main" java.lang.ArithmeticException: / by zero
at learn.Exception.Main.method3(Main.java:18)
at learn.Exception.Main.method2(Main.java:14)
at learn.Exception.Main.method1(Main.java:10)
at learn.Exception.Main.main(Main.java:6)
Exception Hierarchy
Difference between Error and Exception
An Error is also a kind of runtime exception, but the main difference is that an Error cannot be handled by the code, while Exceptions can be handled.
Unchecked / Runtime Exception
These are the exceptions which occurs during runtime and compiler not forcing us to handle them.
public class Main {
public static void main(String[] args) {
Main sampleObj = new Main();
method1();
}
private static void method1() {
throw new ArithmeticException();
}
}
ClassCastException
public class Main {
public static void main(String[] args) {
Object val = 0;
System.out.println((String) val);
}
}
Exception in thread "main" java.lang.ClassCastException:
class java.lang.Integer cannot be cast to class java.lang.String
(java.lang.Integer and java.lang.String are in module java.base
of loader 'bootstrap')
at learn.Exception.Main.main(Main.java:6)
ArithmeticException
public class Main {
public static void main(String[] args) {
int val = 5/0;
}
}
Exception in thread "main" java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String (java.lang.Integer and java.lang.String are in module java.base of loader 'bootstrap')
at learn.Exception.Main.main(Main.java:6)
IndexOutOfBoundException
- ArrayIndexOutOfBoundsException
public class Main {
public static void main(String[] args) {
int[] val = new int[2];
System.out.println(val[3]);
}
}
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 2
at learn.Exception.Main.main(Main.java:6)
- StringIndexOutOfBoundsException
public class Main {
public static void main(String[] args) {
String val = "hello";
System.out.println(val.charAt(5));
}
}
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 5
at java.base/java.lang.StringLatin1.charAt(StringLatin1.java:48)
at java.base/java.lang.String.charAt(String.java:1519)
at learn.Exception.Main.main(Main.java:6)
NullPointerException
public class Main {
public static void main(String[] args) {
String val = null;
System.out.println(val.charAt(0));
}
}
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.charAt(int)" because "val" is null
at learn.Exception.Main.main(Main.java:6)
IllegalArgumentException
If you are sending wrong data then this error is thrown.
public class Main {
public static void main(String[] args) {
int val = Integer.parseInt("acb");
}
}
Exception in thread "main" java.lang.NumberFormatException: For input string: "acb"
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
at java.base/java.lang.Integer.parseInt(Integer.java:668)
at java.base/java.lang.Integer.parseInt(Integer.java:786)
at learn.Exception.Main.main(Main.java:5)
Checked / Compile time Exception
Compiler verifies them during the compile time of the code and if not handled properly, code compilation will fail.
Example:
java: unreported exception java.lang.ClassNotFoundException; must be caught or declared to be thrown
Handle the Exception
Using throws
throws
tells that, this method MIGHT throw this exception (or might not), so please caller you handle it appropriately.
Caller class need to then take Care
public class Main {
public static void main(String[] args) throws ClassNotFoundException {
method1();
}
private static void method1() throws ClassNotFoundException {
throw new ClassNotFoundException();
}
}
Using try/catch
block
public class Main {
public static void main(String[] args) {
method1();
}
private static void method1() {
try{
throw new ClassNotFoundException();
}
catch (ClassNotFoundException exceptionObject){
//handle this exception scenario like logging
exceptionObject.printStackTrace();
}
}
}
Or
public class Main {
public static void main(String[] args) {
try {
method1();
} catch (ClassNotFoundException exceptionObject) {
//handle it
}
}
private static void method1() throws ClassNotFoundException {
throw new ClassNotFoundException();
}
}
Using: try, catch, finally, throw, throws
Try/Catch
Try block specify the code which can throw exception
Try block is followed either by Catch block or finally block
Catch block is used to catch all the exception which can be thrown in the try block.
Multiple catch block can be used.
Catch block, can only catch exception which can be thrown by try block.
Catch all Exception Object
public class Main {
public static void main(String[] args) {
try {
method1("dummy");
}
catch (ClassNotFoundException exceptionObject) {
//handle it
}
catch (Exception exceptionObject){
//handle it
}
}
private static void method1(String name) throws ClassNotFoundException, InterruptedException {
if (name.equals("dummy")) {
throw new ClassNotFoundException();
}
else if (name.equals("interrupted")){
throw new InterruptedException();
}
}
}
Incorrect order
Already Caught by above catch
Catch Multiple Exceptions in One Catch Block
public class Main {
public static void main(String[] args) {
try {
method1("dummy");
}
catch (ClassNotFoundException | InterruptedException exceptionObject) {
//handle it
}
catch (Exception exceptionObject){
//handle it
}
}
private static void method1(String name) throws ClassNotFoundException, InterruptedException {
if (name.equals("dummy")) {
throw new ClassNotFoundException();
}
else if (name.equals("interrupted")){
throw new InterruptedException();
}
}
}
try/catch/finally Or try/finally block
Finally block can be use after try or after catch block.
Finally block will always get executed, either if you just return from try block or from catch block.
At most, we can add only 1 finally block.
Mostly used for closing the object, adding logs etc.
If JVM related issues like out of memory, system shut down or our process is forcefully killed. Then finally block do not get exectued.
Example 1:
public class Main {
public static void main(String[] args) {
try {
method1("dummy");
}
catch (ClassNotFoundException exceptionObject) {
//handle it
}
finally {
// do something here
}
}
private static void method1(String name) throws ClassNotFoundException {
if (name.equals("dummy")) {
throw new ClassNotFoundException();
}
}
}
Example 2: No catch block. (throws in signature)
public class Main {
public static void main(String[] args) throws ClassNotFoundException {
try {
method1("dummy");
}
finally {
// do something here
}
}
private static void method1(String name) throws ClassNotFoundException {
if (name.equals("dummy")) {
throw new ClassNotFoundException();
}
}
}
Example 3: No catch & no throws for run time exception.
public class Main {
public static void main(String[] args) {
try {
method1("dummy");
}
finally {
// do something here
}
}
private static void method1(String name) throws ArithmeticException {
if (name.equals("dummy")) {
throw new ArithmeticException();
}
}
}
Example 4: return in try block
public class Main {
public static void main(String[] args) {
try {
method1("dummy");
return;
}
finally {
System.out.println("Inside finally");
}
}
private static void method1(String name) {
}
}
/* Output ---
Inside finally
*/
throw
It is used to throw a new exception or
To re-throw the exception
public class Main {
public static void main(String[] args) throws ClassNotFoundException {
try {
method1();
}
catch (ClassNotFoundException e){
throw e;
}
}
private static void method1() throws ClassNotFoundException {
throw new ClassNotFoundException();
}
}
Creating custom / User-Defined Exception class
public class MyCustomException extends Exception{
MyCustomException(String message){
super(message);
}
}
Usage
public class Main {
public static void main(String[] args) {
try {
method1();
}
catch (MyCustomException e){
// handle it
}
}
private static void method1() throws MyCustomException {
throw new MyCustomException("some issue arise");
}
}
Why to handle the Exception?
It makes our code clean by separating the error handling code from regular code.
It allows program to recover from the error.
It allow us to add more information, which support debugging.
Improves security, by hiding the sensitive information.
Without Exception handling, we have to do this,
Notice 2 things: Readability and erro code need to be returned.
public int myMethod(int schoolClassNumber){
int errorCode = 0; // 0 means no success
if (schoolClassNumber > 0 && schoolClassNumber <= 12){
int noOfStudents = getStudentCapacityOfClass(schoolClassNumber);
if (noOfStudents != 0){
String[] names = new String[noOfStudents];
if (names!=null && names.length>0){
names[0] = "new Value";
}
else{
return -3;
}
}
else{
return -2;
}
}
else{
errorCode = -1;
}
return errorCode;
}
With Exception Handling
public int myMethod(int schoolClassNumber){
try{
int noOfStudents = getStudentCapacityOfClass(schoolClassNumber);
String[] names = new String[noOfStudents];
names[0] = "new Value";
}
catch (IndexOutOfBoundsException exceptionObject){
// do something
}
catch (Exception exceptionObject){
// do something
}
return -1;
}
Expensive
Remember, Exception hanlding is little expensive, if stack trace is huge and it is not handled or handled at parent class.
If the throws exception propagates from caller to caller this is stored in stack memory. so this also occupies some space. (Like Recurrsion)
Try to avoid using exception handling, if you can. Or Handle the exception in the class where it was originated. In this away it will be super fast.
Example:
public int myMethod(int a, int b){
int val;
try{
val = a/b;
}
catch (ArithmeticException exp){
val = -1;
}
return val;
}
Simplified: (Faster Approach)
public int myMethod(int a, int b){
if (b==0) return -1;
int val = a/b;
return val;
}