Exceptions refer to various unexpected situations, such as: file cannot be found, network connection failure, illegal parameters, etc.
An exception is an event that occurs during program execution and interferes with the normal flow of instructions.
What You Need
- About 11 minutes
- A favorite text editor or IDE
- Java 8 or later
1. Exception Hierarchy
Java describes various exceptions through numerous sub classes of the Throwable class in the API.
Thus java exceptions are objects, instances of a Throwable subclass.

1.1 Throwable
Throwable is the super class of all errors and exceptions in Java.
Throwable contains two sub classes : Error and Exception, which are generally used to indicate that an exception has occurred.
1.2 Error
Error class and its sub classes stand for errors that cannot be handled in the program, indicating that a serious error has occurred in the running application.
This type of error generally indicates a problem with the JVM while the code is running.
Such as Virtual MachineError, NoClassDefFoundError, OutOfMemoryError, StackOverflowError etc.
When such an error occurs, the JVM terminates the application.
1.3 Exception
Exception class and its sub classes stand for exceptions that the program itself can catch and handle.
The exceptions are divided into two categories : run-time exception (unchecked exception) and compile-time exception (checked exception).
- Run Time Exception :
- They are subclasses of the RuntimeException class, such as NullPointerException, IndexOutOfBoundsException etc;
- They are unchecked exceptions, we can choose to capture them in the program or not handle them;
- They are generally caused by program logic errors, and the program should try to avoid the occurrence of such exceptions from a logical perspective.
- Compile Time Exception :
- They are exceptions other than RuntimeException, such as IOException, SQLException etc as well as user-defined Exceptions.
- They are checked exceptions, from the perspective of program syntax, if this kind of exceptions are not handled, the program will not be compiled.
2. Exception Basis
2.1 Exception Keywords
- try : used for monitoring, place the code that may throw exceptions within the try statement block, when an exception occurs within the try statement block, the exception is thrown;
- catch : used to catch exceptions, it is used to catch exceptions that occur in the try statement block;
- finally : will always be executed, it is mainly used to recycle physical resources (such as database connections, network connections, and disk files) opened in try blocks, after execution of finally block is completed, it will come back to execute the return or throw statement in the try or catch block, if a statement such as return or throw is used in the finally block, it will not jump back to execution;
- throw : used to throw exceptions;
- throws : used in method signatures to declare exceptions that may be thrown by the method.
2.2 Declare Exception (throws)
In Java, the currently executed statement must belong to a certain method, and the Java interpreter calls the main method to start executing the program.
If there is a checked exception in the method, if it is not caught, the exception must be explicitly declared in the method header to inform the method caller that this method has an exception and needs to be handled.
To declare an exception in a method, use the keyword throws in the method header, followed by the exception to be declared.
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class ExceptionTest1 {
public static void main(String[] args) throws IOException {
readFile("this_is_a_test.txt");
}
private static void readFile(String fileName) throws IOException {
File file = new File(fileName);
FileInputStream fis = new FileInputStream(file);
byte[] bytes = fis.readAllBytes();
System.out.println(new String(bytes));
}
}
The output of above code snippet is below :
Exception in thread "main" java.io.FileNotFoundException: this_is_a_test.txt (No such file or directory)
at java.base/java.io.FileInputStream.open0(Native Method)
at java.base/java.io.FileInputStream.open(FileInputStream.java:213)
at java.base/java.io.FileInputStream.<init>(FileInputStream.java:152)
at ExceptionTest1.readFile(ExceptionTest1.java:13)
at ExceptionTest1.main(ExceptionTest1.java:7)
If multiple exceptions are declared, separate them with commas.
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
public class ExceptionTest2 {
public static void main(String[] args)
throws SecurityException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException,
IllegalAccessException, NoSuchFieldException {
Person p = new Person("tom", 18);
System.out.println(p);
Class<?> clazz = p.getClass();
Field name = clazz.getDeclaredField("nam");
System.out.println("name = " + name.get(p));
}
private static class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
}
The output of above code snippet is below :
Person [name=tom, age=18]
Exception in thread "main" java.lang.NoSuchFieldException: nam
at java.base/java.lang.Class.getDeclaredField(Class.java:2782)
at ExceptionTest2.main(ExceptionTest2.java:14)
If it is an uncheckable exception, there is no need to use the throws keyword.
The compilation will still pass smoothly, but the exception will be thrown by the system at runtime.
public class ExceptionTest3 {
public static void main(String[] args) {
int result = 1 / 0;
System.out.println(result);
}
}
The output of above code snippet is below :
Exception in thread "main" java.lang.ArithmeticException: / by zero
at ExceptionTest3.main(ExceptionTest3.java:3)
2.3 Throw Exception (throw)
In most cases, there is no need to manually throw exceptions, because most methods in Java either already handle exceptions or declare exceptions.
But it is also possible to throw an exception manually by using throw keyword.
public class ExceptionTest4 {
public static void main(String[] args) {
int result = divide(1, 0);
System.out.println(result);
}
private static int divide(int a, int b) {
if (b == 0) {
throw new ArithmeticException("b can not be 0");
}
return a / b;
}
}
The output of above code snippet is below :
Exception in thread "main" java.lang.ArithmeticException: b can not be 0
at ExceptionTest4.divide(ExceptionTest4.java:10)
at ExceptionTest4.main(ExceptionTest4.java:3)
2.4 Capture Exception
In java, to capture a throwed exception, usually we can use below :
- try-catch;
- try-catch-finally;
- try-finally;
- try-with-resource.
try-catch
If an exception is thrown during a sequence of statements inside a try-catch block, the sequence of statements is interrupted and the flow of control will skip directly to the catch-block.
Multiple exception types can be caught in a try-catch statement block, and different types of exceptions can be handled differently.
The same catch can also capture multiple types of exceptions, separated by |
import java.lang.reflect.Field;
public class ExceptionTest5 {
public static void main(String[] args) {
Person p = new Person("tom", 18);
System.out.println(p);
System.out.println();
Class<?> clazz = p.getClass();
Field name = null;
try {
name = clazz.getDeclaredField("nam");
} catch (NoSuchFieldException | SecurityException e) {
System.out.println("Exception found when getting declared field");
System.out.println();
e.printStackTrace();
}
System.out.println();
try {
System.out.println("name = " + name.get(p));
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NullPointerException e) {
System.out.println("Exception found when getting name");
System.out.println();
e.printStackTrace();
}
}
private static class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
}
The output of above code snippet is below :
Person [name=tom, age=18]
Exception found when getting declared field
java.lang.NoSuchFieldException: nam
at java.base/java.lang.Class.getDeclaredField(Class.java:2782)
at ExceptionTest5.main(ExceptionTest5.java:15)
Exception found when getting name
java.lang.NullPointerException: Cannot invoke "java.lang.reflect.Field.get(Object)" because "name" is null
at ExceptionTest5.main(ExceptionTest5.java:25)
try-catch-finally
It is possible to attach a finally-clause to a try-catch block.
The code inside the finally clause will always be executed, even if an exception is thrown from within the try or catch block.
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class ExceptionTest6 {
public static void main(String[] args) {
readFile("this_is_a_test.txt");
}
private static void readFile(String fileName) {
File file = new File(fileName);
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
System.out.println("This line should not be printed, below lines should not be executed");
byte[] bytes = fis.readAllBytes();
System.out.println(new String(bytes));
} catch (FileNotFoundException e) {
System.out.println("Caught FileNotFoundException!!!");
e.printStackTrace();
} catch (IOException e) {
System.out.println("Caught IOException!!!");
e.printStackTrace();
} finally {
System.out.println("Execute in finally.");
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
System.out.println("The end of program.");
}
}
The output of above code snippet is below :
Caught FileNotFoundException!!!
java.io.FileNotFoundException: this_is_a_test.txt (No such file or directory)
at java.base/java.io.FileInputStream.open0(Native Method)
at java.base/java.io.FileInputStream.open(FileInputStream.java:213)
at java.base/java.io.FileInputStream.<init>(FileInputStream.java:152)
at ExceptionTest6.readFile(ExceptionTest6.java:16)
at ExceptionTest6.main(ExceptionTest6.java:8)
Execute in finally.
The end of program.
If the code has a return statement inside the try or catch block, the code inside the finally-block will get executed before returning from the method.
public class ExceptionTest7 {
public static void main(String[] args) {
System.out.println(divide(4, 2));
System.out.println();
System.out.println(divide(4, 0));
}
private static int divide(int a, int b) {
int c = 0;
try {
c = a / b;
System.out.println("I am in try block.");
return c;
} catch (ArithmeticException e) {
e.printStackTrace();
return c;
} finally {
System.out.println("I am in finally block.");
}
}
}
The output of above code snippet is below :
I am in try block.
I am in finally block.
2
java.lang.ArithmeticException: / by zero
at ExceptionTest7.divide(ExceptionTest7.java:13)
at ExceptionTest7.main(ExceptionTest7.java:7)
I am in finally block.
0
try-finally
It is possible to use try-finally directly without catch block.
If an exception occurs in the try block, the statements after the exception code will no longer be executed, and the finally statement will be executed directly.
public class ExceptionTest8 {
public static void main(String[] args) {
try {
System.out.println("I am in try block");
int x = 1 / 0;
System.out.println("This line will not be printed");
} finally {
System.out.println("I am in finally block");
}
System.out.println("This line will not be printed");
}
}
The output of above code snippet is below :
I am in try block
I am in finally block
Exception in thread "main" java.lang.ArithmeticException: / by zero
at ExceptionTest8.main(ExceptionTest8.java:6)
If the try block does not throw an exception, the finally statement will be executed after the try block is executed.
public class ExceptionTest9 {
public static void main(String[] args) {
try {
System.out.println("I am in try block");
int x = 4 / 2;
System.out.println(x);
} finally {
System.out.println("I am in finally block");
}
System.out.println("The end of program");
}
}
The output of above code snippet is below :
I am in try block
2
I am in finally block
The end of program
The try-finally can be used in code that does not need to catch exceptions to ensure that the resource is closed after use :
- After executing the corresponding operation in the IO stream, close the corresponding resource;
- Use the Lock object to ensure thread synchronization and finally ensure that the lock will be released;
- When connecting to the database code, close the connection operation etc.
try-with-resource
If there is an exception in try block and at the same time there is another exception throwed in finally block, the original exception will be suppressed.
public class ExceptionTest10 {
public static void main(String[] args) {
try {
throw new ArithmeticException("this is an arithmetic exception");
} finally {
throw new RuntimeException("this is a runtime exception");
}
}
}
The output of above code snippet is below :
Exception in thread "main" java.lang.RuntimeException: this is a runtime exception
at ExceptionTest10.main(ExceptionTest10.java:6)
So, if there is code for closing a resource in finally block but it throws an exception, it will suppress the original exception.
Since java 7, there is a more elegant way to automatically release resources : try-with-resource.
The automatically released resources need to be classes that implement the AutoCloseable interface.
It has to overwrite its close method in which we need to release resources.
The exception in close method will be suppressed but not the original one.
public class ExceptionTest11 {
public static void main(String[] args) throws Exception {
try (MyCloseable mc = new MyCloseable()) {
throw new ArithmeticException("this is an arithmetic exception");
}
}
private static class MyCloseable implements AutoCloseable {
@Override
public void close() throws Exception {
throw new RuntimeException("this is a runtime exception");
}
}
}
The output of above code snippet is below :
Exception in thread "main" java.lang.ArithmeticException: this is an arithmetic exception
at ExceptionTest11.main(ExceptionTest11.java:4)
Suppressed: java.lang.RuntimeException: this is a runtime exception
at ExceptionTest11$MyCloseable.close(ExceptionTest11.java:11)
at ExceptionTest11.main(ExceptionTest11.java:5)
Suppressed exceptions will be added to the original exceptions by the addSusppressed method.
To get the suppressed exception list, we can call the getSuppressed method.
public class ExceptionTest12 {
public static void main(String[] args) {
try (MyCloseable mc = new MyCloseable()) {
throw new ArithmeticException("this is an arithmetic exception");
} catch (Exception e) {
e.printStackTrace();
Throwable[] suppressed = e.getSuppressed();
System.out.println();
System.out.println("Suppressed :");
System.out.println();
for (int i = 0; i < suppressed.length; i++) {
suppressed[i].printStackTrace();
}
}
}
private static class MyCloseable implements AutoCloseable {
@Override
public void close() throws Exception {
throw new RuntimeException("this is a runtime exception");
}
}
}
The output of above code snippet is below :
java.lang.ArithmeticException: this is an arithmetic exception
at ExceptionTest12.main(ExceptionTest12.java:4)
Suppressed: java.lang.RuntimeException: this is a runtime exception
at ExceptionTest12$MyCloseable.close(ExceptionTest12.java:22)
at ExceptionTest12.main(ExceptionTest12.java:5)
Suppressed :
java.lang.RuntimeException: this is a runtime exception
at ExceptionTest12$MyCloseable.close(ExceptionTest12.java:22)
at ExceptionTest12.main(ExceptionTest12.java:5)