Exception Handling|Sessions 68 to 77¶
- Java Exception Handling by Durga sir
10h - Create a Custom Exception in Java
- Exception Handling in Java
What is an Exception?¶
Any unexpected events that occur during program execution are called exceptions, such as FileNotFoundException. The primary purpose of exception handling is to ensure the program terminates gracefully.
class Test {
public static void main() {
doStuff();
}
public static void doStuff() {
doOtherStuff();
}
public static void doOtherStuff() {
System.out.println("Hello");
}
}
Test.main();
Hello
// example 1
class Test {
public static void main() {
doStuff();
}
public static void doStuff() {
doOtherStuff();
}
// the method where the exception occurs is responsible for creating the exception object
// along with all relevant (name, description, location) information.
public static void doOtherStuff() {
System.out.println(10/0);
}
}
Test.main();
--------------------------------------------------------------------------- java.lang.ArithmeticException: / by zero at Test.doOtherStuff(#12:14) at Test.doStuff(#12:8) at Test.main(#12:4) at .(#14:1)
// example 2
class Test {
public static void main() {
doStuff();
System.out.println(10/0);
}
public static void doStuff() {
doOtherStuff();
System.out.println("Hi");
}
public static void doOtherStuff() {
System.out.println("Hello");
}
}
Test.main();
Hello Hi
--------------------------------------------------------------------------- java.lang.ArithmeticException: / by zero at Test.main(#12:5) at .(#15:1)
Every exception occurs at runtime whether it is checked or unchecked.
Types of Exception¶
There are 2 types of exception:
- Checked Exception
- The exceptions which are checked by the compiler for smooth execution of program at runtime are called checked exception or compile time exception. These exceptions must be caught by
try-catchor declare to be thrown bythrows.
- The exceptions which are checked by the compiler for smooth execution of program at runtime are called checked exception or compile time exception. These exceptions must be caught by
- Unchecked Exception
- The exceptions which are not checked by the compiler whether programmer handling it or not such exceptions are called unchecked exception or run time exception.
import java.io.*;
class ABC {
public static void main() {
// checked exception: unreported exception FileNotFoundException; must be caught or declared to be thrown
PrintWriter pw = new PrintWriter("./abc.txt");
pw.println("Hello");
}
}
ABC.main();
| PrintWriter pw = new PrintWriter("./abc.txt"); unreported exception java.io.FileNotFoundException; must be caught or declared to be thrown
class ABC {
public static void main() {
try {
PrintWriter pw = new PrintWriter("./abc.txt");
} catch (FileNotFoundException e) {
System.out.println(e.getMessage());
}
// unchecked exception
System.out.println(10 / 0);
}
}
ABC.main();
--------------------------------------------------------------------------- java.lang.ArithmeticException: / by zero at ABC.main(#16:10) at .(#17:1)
System.out.println("Statement 1");
System.out.println(10/0);
System.out.println("Statement 2");
Statement 1
--------------------------------------------------------------------------- java.lang.ArithmeticException: / by zero at .(#19:1)
System.out.println("Statement 1");
try {
System.out.println(10/0);
} catch (ArithmeticException e) {
System.out.println(e.toString());
}
System.out.println("Statement 2");
Statement 1 java.lang.ArithmeticException: / by zero Statement 2
Print the Exception Information¶
These methods are available in Throwable class.
e.getMessage()e.toString()e.printStackTrace()
// worst practice
try {
} catch (Exception e) {
}
// best practice
try {
} catch (ArithemeticException e) {
} catch (IOException e) {
} catch (FileNotFoundException e) {
} catch (Exception e) {
}
try {
System.out.println(10/0);
} catch (ArithmeticException e) {
System.out.println(e.getMessage());
}
/ by zero
try {
System.out.println(10/0);
} catch (ArithmeticException e) {
System.out.println(e); // e.toString()
}
java.lang.ArithmeticException: / by zero
try {
System.out.println(10/0);
} catch (ArithmeticException e) {
e.printStackTrace();
}
java.lang.ArithmeticException: / by zero at REPL.$JShell$25.do_it$($JShell$25.java:15) at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) at java.base/java.lang.reflect.Method.invoke(Method.java:580) at io.github.spencerpark.ijava.execution.IJavaExecutionControl.lambda$execute$1(IJavaExecutionControl.java:95) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) at java.base/java.lang.Thread.run(Thread.java:1583)
Loopholes¶
- Order of
catchblocks are important- First child blocks, at the end parent block
try {
System.out.println(10/0);
} catch (Exception e) {
System.out.println(e.getMessage());
} catch (ArithmeticException e) {
System.out.println(e.getMessage());
}
| } catch (ArithmeticException e) { | System.out.println(e.getMessage()); | } exception java.lang.ArithmeticException has already been caught
// best practice
try {
System.out.println(10/0);
} catch (ArithmeticException e) {
System.out.println(e);
} catch (Exception e) {
System.out.println(e.getMessage());
}
java.lang.ArithmeticException: / by zero
try-catch-finally block¶
try {}
catch () {}
try {}
catch (X e) {}
catch (Y e) {}
// invalid
try {}
catch (X e) {}
catch (X e) {}
try {}
finally {}
try {}
catch (X e) {}
try {}
finally {}
try {}
catch (X e) {}
try {}
catch (Y e) {}
// Error: try without catch/finally
try {}
// Error: catch without try
catch (Y e) {}
// Error: finally without try
finally {}
// Error: catch without try
try {}
finally {}
catch (A e) {}
// Error: try without finally/catch
// Error: catch without try
try {}
System.out.println("Hello");
catch (A e) {}
---
try {
try {
} catch (X e) {}
} catch (X e) {}
---
try {
try {}
finally {}
} catch (X e) {}
---
try {
} catch (X e) {
} finally {
try {
} catch (A e) {
}
}
throw keyword¶
- The
throwkeyword is primarily used to raise custom exceptions.
try {
throw new ArithmeticException("Divison by 0 is not possible");
} catch (ArithmeticException e) {
System.out.println(e.getMessage());
}
Divison by 0 is not possible
// example 1
class Test {
static ArithmeticException e = new ArithmeticException("Division by 0");
public static void main() {
throw e;
}
}
Test.main();
--------------------------------------------------------------------------- java.lang.ArithmeticException: Division by 0 at Test.<clinit>(#12:3) at .(#29:1)
class Test {
static ArithmeticException e; // e points to NULL
public static void main() {
throw e;
}
}
Test.main();
--------------------------------------------------------------------------- java.lang.NullPointerException: Cannot throw exception because "REPL.$JShell$12E$Test.e" is null at Test.main(#12:5) at .(#30:1)
// example 2
System.out.println(10/0);
System.out.println("Hello");
--------------------------------------------------------------------------- java.lang.ArithmeticException: / by zero at .(#31:2)
class Test {
public static void main() {
throw new ArithmeticException("Division by 0"); // used throw to explicitly raise error, so program stops here
System.out.println("Hello"); // error: unreachable statement
}
}
Test.main();
| System.out.println("Hello"); // error: unreachable statement unreachable statement
// example 3
class Test {
public static void main() {
throw new Test(); // you can use throw only throwable objects
}
}
Test.main();
| throw new Test(); // you can use throw only throwable objects incompatible types: Test cannot be converted to java.lang.Throwable
class Test extends RuntimeException { // Exception in thread "main" Test
public static void main() {
throw new Test();
}
}
throws Keyword¶
- The
throwskeyword is primarily used with checked exceptions to delegate responsibility to the caller.
class Main {
public static void main() {
PrintWriter pw = new PrintWriter("abc.txt");
pw.println("Hello");
}
}
Main.main();
| PrintWriter pw = new PrintWriter("abc.txt"); unreported exception java.io.FileNotFoundException; must be caught or declared to be thrown
class Test {
public static void main() {
Thread.sleep(1000);
}
}
Test.main();
| Thread.sleep(1000); unreported exception java.lang.InterruptedException; must be caught or declared to be thrown
To solve the unreported exception problem in the above code, there are two approaches:
- Using the
throwskeyword - Using a
try-catchblockt.
class Test {
public static void main() throws InterruptedException{
Thread.sleep(1000);
}
}
Test.main();
class Test {
public static void main() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println(e);
}
}
}
Test.main();
class Test {
public static void main() {
try {
doStuff();
} catch (InterruptedException e) {
System.out.println(e);
}
}
public static void doStuff() throws InterruptedException {
doOtherStuff();
}
public static void doOtherStuff() throws InterruptedException {
Thread.sleep(100);
}
}
Test.main();
class Test {
public static void main() {
try {
doStuff();
} catch (InterruptedException e) {
System.out.println(e);
}
}
public static void doStuff() {
doOtherStuff();
}
public static void doOtherStuff() {
Thread.sleep(100);
}
}
Test.main();
| } catch (InterruptedException e) { | System.out.println(e); | } exception java.lang.InterruptedException is never thrown in body of corresponding try statement | Thread.sleep(100); unreported exception java.lang.InterruptedException; must be caught or declared to be thrown
// Example 1
// throws keyword is only valid for method and constructor, not class
class Test throws Exception {
public static void test() throws Exception {}
public static void main() throws Exception {}
}
| class Test throws Exception { '{' expected
// Example 2
class Test extends RuntimeException {
public static void main() throws Test {}
}
Test.main();
class Test {
public static void main() throws Test {}
}
| public static void main() throws Test {} incompatible types: Test cannot be converted to java.lang.Throwable
// Example 3
class Test {
public static void main() {
throw new Exception(); // checked exception
}
}
| throw new Exception(); // checked exception unreported exception java.lang.Exception; must be caught or declared to be thrown
// Exception in thread "main" java.lang.Error
class Test {
public static void main(){
throw new Error(); // unchecked exception
}
}
Test.main();
--------------------------------------------------------------------------- java.lang.Error: null at Test.main(#12:4) at .(#38:1)
Checked Exceptions (Fully Checked)¶
Fully checked exceptions are exceptions that must be either:
- Handled in a
try-catchblock, or - Declared in the method signature using
throws.
These exceptions are part of the Exception class but do not extend RuntimeException.
- IOException
- SQLException
- ClassNotFoundException
- FileNotFoundException
- InterruptedException
Must be handled either by a try-catch block or by declaring throws in the method signature.
Unchecked Exceptions (Runtime Exceptions)¶
- NullPointerException
- ArrayIndexOutOfBoundsException
- ArithmeticException
- ClassCastException
Partially Checked Exceptions¶
Partial checked exceptions could refer to certain exceptions that technically can be thrown during normal application flow but are not strictly enforced by the compiler to be either caught or declared in the method signature.
- IllegalArgumentException
- IllegalStateException
Errors¶
- OutOfMemoryError
- StackOverflowError
- VirtualMachineError
class Test {
public static void main() {
try {
System.out.println("Hello");
} catch (ArithmeticException e) { // unchecked
System.out.println(e);
}
}
}
Test.main();
Hello
class Test {
public static void main() {
try {
System.out.println("Hello");
} catch (Exception e) { // partial checked
System.out.println(e);
}
}
}
Test.main();
Hello
import java.io.*;
class Test {
public static void main() {
try {
System.out.println("Hello");
} catch (IOException e) { // fully checked
System.out.println(e);
}
}
}
Test.main();
| } catch (IOException e) { // fully checked | System.out.println(e); | } exception java.io.IOException is never thrown in body of corresponding try statement
// InterruptedException is a fully checked exception and must be either caught or declared
class Test {
public static void main() {
try {
System.out.println("Hello");
} catch (InterruptedException e) { // fully checked
System.out.println(e);
}
}
}
Test.main();
| } catch (InterruptedException e) { // fully checked | System.out.println(e); | } exception java.lang.InterruptedException is never thrown in body of corresponding try statement
class Test {
public static void main() {
try {
System.out.println("Hello");
} catch (Error e) { // unchecked
System.out.println(e);
}
}
}
Test.main();
Hello
Keywords in Exception Handling¶
- try: Used to enclose risky code that might throw exceptions.
- catch: Used to handle exceptions that occur within the
tryblock. - finally: Used to execute cleanup code, regardless of whether an exception was thrown or not.
- throw: Used to explicitly hand over a custom exception object to the JVM.
- throws: Used to delegate the responsibility of exception handling to the caller of a method.
Possible Compile-Time Exception Messages¶
- Unreported Exception X; must be caught or declared to be thrown.
- Exception X has already been caught.
- Exception X is never thrown in the body of the corresponding
trystatement. - Unreachable Statement
- Incompatible Types
found: X required `java.lang.Throwable`
trywithoutcatchorfinallycatchwithouttryfinallywithouttry
Custome Exception¶
- Custom exceptions are user-defined exceptions that extend the
ExceptionorRuntimeExceptionclass.
class TooYoungException extends RuntimeException {
TooYoungException(String msg) {
super(msg);
}
}
class TooOldException extends RuntimeException {
TooOldException(String msg) {
super(msg);
}
}
import java.util.Scanner;
class CastException {
public static void eligible(int age) {
// int age = Integer.parseInt(args[0]);
// Scanner scanner = new Scanner(System.in);
// System.out.println("Enter your age: ");
// int age = scanner.nextInt();
// scanner.close();
if (age > 60) {
throw new TooYoungException("Please wait some more time, definitely you will get best matched");
} else if (age < 18) {
throw new TooOldException("Your age is already crossed for marriage age, no chance of getting married.");
} else {
System.out.println("You'll get matched details soon by email");
}
}
}
CastException.eligible(18);
You'll get matched details soon by email
CastException.eligible(65);
--------------------------------------------------------------------------- REPL.$JShell$42$TooYoungException: Please wait some more time, definitely you will get best matched at CastException.eligible(#45:1) at .(#47:1)
CastException.eligible(15);
--------------------------------------------------------------------------- REPL.$JShell$43$TooOldException: Your age is already crossed for marriage age, no chance of getting married. at CastException.eligible(#45:1) at .(#48:1)
Top 10 Java Exceptions¶
NoClassDefFoundError¶
- When JVM unable to find the
.classfile, it will raise the error. - ClassNotFoundException vs NoClassDefFoundError
- It is child of
RuntimeExceptionhence it isunchecked
ArrayIndexOutOfBoundsException¶
- Java ArrayIndexOutOfBoundsException
- It is child of
RuntimeExceptionhence it isunchecked - If a piece of code tries to access an illegal index of an array, the respective method throws an
ArrayIndexOutOfBoundException.
int[] x = new int[] {1, 2, 3};
System.out.println(x[0]);
System.out.println(x[10]);
1
--------------------------------------------------------------------------- java.lang.ArrayIndexOutOfBoundsException: Index 10 out of bounds for length 3 at .(#51:1)
NullPointerException¶
- Helpful NullPointerExceptions in Java
- It is child of
RuntimeExceptionhence it isunchecked - If an application attempts to use
nullwhere it actually requires an object instance, the method will throw aNullPointerException.
String s = null;
s.length();
--------------------------------------------------------------------------- java.lang.NullPointerException: Cannot invoke "String.length()" because "REPL.$JShell$52.s" is null at .(#53:1)
ClassCastException¶
- Explanation of ClassCastException in Java
- It is child of
RuntimeExceptionhence it isunchecked - At runtime, if the code attempts to downcast an object to a subtype of which it isn’t an instance, the method throws a
ClassCastException.
// child class can cast to parent class
String str = new String("Hello");
Object o = (Object) str;
// not vice versa
Object o = new Object();
String str = (Object) o;
| String str = (Object) o; incompatible types: java.lang.Object cannot be converted to java.lang.String
// valid
Object o = new String("Hello");
String s = (String) o;
StackOverflowError¶
- It is child of
RuntimeExceptionhence it isunchecked - The StackOverflowError in Java
class Test {
public static void m1() {
m2();
}
public static void m2() {
m1();
}
public static void main() {
m1();
}
}
// Test.main();
ExceptionInInitializerError¶
- It is child of
RuntimeExceptionhence it isunchecked - When Does Java Throw the ExceptionInInitializerError?
class Test {
public static int x = 10 / 0;
}
Test.x;
--------------------------------------------------------------------------- java.lang.ExceptionInInitializerError: null at .(#56:1)
class Test {
static {
String s = null;
System.out.println(s.length());
}
}
Test t = new Test();
--------------------------------------------------------------------------- java.lang.ExceptionInInitializerError: null at .(#57:1)
IllegalArgumentException¶
- It is child of
RuntimeExceptionhence it isunchecked - A method throws an
IllegalArgumentExceptionif we call it with some illegal or inappropriate arguments. - IllegalArgumentException or NullPointerException for a Null Parameter?
Thread t = new Thread();
t.setPriority(7); // range(1,10)
t.setPriority(15);
--------------------------------------------------------------------------- java.lang.IllegalArgumentException: null at java.base/java.lang.Thread.setPriority(Thread.java:1868) at .(#59:3)
NumberFormatException¶
- Java throws
NumberFormatException– an unchecked exception – when it cannot convert a String to a number type. - Understanding the NumberFormatException in Java
- It is class of
IllegalArgumentException.
int i = Integer.parseInt("10");
int i = Integer.parseInt("ten");
--------------------------------------------------------------------------- java.lang.NumberFormatException: For input string: "ten" at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67) at java.base/java.lang.Integer.parseInt(Integer.java:662) at java.base/java.lang.Integer.parseInt(Integer.java:778) at .(#60:1)
IllegaStateException¶
IllegalStateExceptionsignals that a method’s been invoked at an illegal or inappropriate time.
Iterator<Integer> intListIterator = new ArrayList<>().iterator();
intListIterator.remove();
| Iterator<Integer> intListIterator = new ArrayList<>().iterator(); incompatible types: java.util.Iterator<java.lang.Object> cannot be converted to java.util.Iterator<java.lang.Integer>
AssertionError¶
- It is child of
Errorhence it isunchecked. - An
AssertionErroris thrown when a Java program encounters a failed assertion
// by default, assertions are disabled in Java. To enable assertions,
// you need to use the `-ea` flag when running the Java program.
// javac Main.java
// java -ea Main
class Main {
public static void main() {
int num = 5;
assert num > 0: "Number must be positive";
System.out.println("Number is positive: " + num);
}
}
Main.main();
Number is positive: 5
try with resources¶
- Introduced in Java 1.7
- Java provides the
try-with-resourcesstatement, which ensures that resources are closed automatically after usage, without the need to explicitly define them in thefinallyblock.
try (FileWriter fw = new FileWriter("output.txt"); FileReader fr = new FileReader("output.txt")) {
// reassignment here is compilation error
} catch () {
}
// valid since 1.7
// autocloseable resources: netwrok, database, io
try () {
}
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
String filePath = "example.txt";
BufferedReader reader = null;
// 1.6
try {
reader = new BufferedReader(new FileReader(filePath));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
System.out.println(e);
} finally {
if (reader != null) {
reader.close();
}
}
java.io.FileNotFoundException: example.txt (No such file or directory)
String filePath2 = "example.txt";
// 1.7
try (BufferedReader reader = new BufferedReader(new FileReader(filePath2))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
System.out.println(e);
}
java.io.FileNotFoundException: example.txt (No such file or directory)
try (int x = 10/0;) {
System.out.println(x);
}
| try (int x = 10/0;) { incompatible types: try-with-resources not applicable to variable type (int cannot be converted to java.lang.AutoCloseable)
Multi catch block¶
// there should be no relationship between the exception types (no parent-child or child-parent)
// in a multi-catch, else a compilation error will occur.
try {
} catch (ChildException | Exception e) {
}
try {
int x = 10/0;
BufferedReader reader = new BufferedReader(new FileReader("example.txt"));
String line = reader.readLine();
} catch (ArithmeticException | IOException e) {
System.out.println(e);
}
java.lang.ArithmeticException: / by zero
try {
String s = null;
System.out.println(s.length());
int x = 10/0;
} catch (ArithmeticException | NullPointerException e) {
System.out.println(e);
}
java.lang.NullPointerException: Cannot invoke "String.length()" because "<local0>" is null
try {
int x = 10 / 0;
} catch (ArithmeticException | Exception e) { // a specific exception should not be caught with a general one (Exception)
System.out.println(e);
}
| } catch (ArithmeticException | Exception e) { // a specific exception should not be caught with a general one (Exception) Alternatives in a multi-catch statement cannot be related by subclassing Alternative java.lang.ArithmeticException is a subclass of alternative java.lang.Exception
// it's valid
try {
int l = Integer.parseInt("hell");
} catch (ArithmeticException e) {
System.out.println(e);
} catch (Exception e) {
System.out.println(e);
}
java.lang.NumberFormatException: For input string: "hell"