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 7 minutes
- A favorite text editor or IDE
- Java 8 or later
4. Deep Understanding Of Exceptions
4.1 JVM exception handling mechanism
When talking about the JVM exception handling mechanism, we need to mention the Exception Table.
Below code is a very simple example used to catch and handle a null pointer exception.
1public class ExceptionTest16 {
2 public static void main(String[] args) {
3 try {
4 throw new NullPointerException("This is my null pointer exception");
5 } catch (Exception e) {
6 e.printStackTrace();
7 }
8 }
9}
We use javap -c ClassName to obtain its disassemble byte code in order to see the Exception table.
public class ExceptionTest16 {
public ExceptionTest16();
Code:
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: new #16 // class java/lang/NullPointerException
3: dup
4: ldc #18 // String This is my null pointer exception
6: invokespecial #20 // Method java/lang/NullPointerException."<init>":(Ljava/lang/String;)V
9: athrow
10: astore_1
11: aload_1
12: invokevirtual #23 // Method java/lang/Exception.printStackTrace:()V
15: return
Exception table:
from to target type
0 10 10 Class java/lang/Exception
}
The exception table contains information about one or more exception handlers.
The information includes the following :
- from : the starting point where the exception may occur;
- to : the end point where an exception may occur;
- target : the location of the exception handler after an exception occurs between from and to;
- type : the class information of the exception handled by the exception handler.
If we look at the code snippet, when the program executes at line 4, it will throw a null pointer exception.
In the byte code, the line 4 of source code correspond to 0 – 9.
According to the exception table in the byte code, from 0 to 9 [0, 10), if there is any java.lang.Exception, it will go to 10 to handle the exception.
Lines from 10 to 12 of the byte code correspond to line 6 of the source code, which is located in the catch block to handle exception throwed in try block.
4.2 Example of try-catch-finally
In below code snippet, two exceptions will be occurred :
- An arithmetic exception will be occurred in the try block at line 5;
- A number format exception will be occurred in the catch block at line 8.
The execution flow of this code snippet is below :
- at line 4 : print “In Try” in console;
- at line 5 : divisor is 0, so throw an arithmetic exception, which leads to enter into the catch block;
- at line 7 : print “In Catch” in console;
- at line 8 : can not parse space into integer, so need to throw number format exception, but firstly enter into the finally block;
- at line 11 : print “In Finally” in console;
- at line 13 : throw number format exception of line 8.
1public class ExceptionTest17 {
2 public static void main(String[] args) {
3 try {
4 System.out.println("In Try.");
5 int x = 1 / 0;
6 } catch (ArithmeticException e) {
7 System.out.println("In Catch.");
8 Integer.parseInt(" ");
9 e.printStackTrace();
10 } finally {
11 System.out.println("In finally.");
12 }
13 }
14}
Below is the output of above code snippet :
In Try.
In Catch.
In finally.
Exception in thread "main" java.lang.NumberFormatException: For input string: " "
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
at java.base/java.lang.Integer.parseInt(Integer.java:648)
at java.base/java.lang.Integer.parseInt(Integer.java:778)
at ExceptionTest17.main(ExceptionTest17.java:8)
Below is the byte code of this code snippet :
public class ExceptionTest17 {
public ExceptionTest17();
Code:
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #16 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #22 // String In Try.
5: invokevirtual #24 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: iconst_1
9: iconst_0
10: idiv
11: istore_1
12: goto 56
15: astore_1
16: getstatic #16 // Field java/lang/System.out:Ljava/io/PrintStream;
19: ldc #30 // String In Catch.
21: invokevirtual #24 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
24: ldc #32 // String
26: invokestatic #34 // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
29: pop
30: aload_1
31: invokevirtual #40 // Method java/lang/ArithmeticException.printStackTrace:()V
34: getstatic #16 // Field java/lang/System.out:Ljava/io/PrintStream;
37: ldc #45 // String In finally.
39: invokevirtual #24 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
42: goto 64
45: astore_2
46: getstatic #16 // Field java/lang/System.out:Ljava/io/PrintStream;
49: ldc #45 // String In finally.
51: invokevirtual #24 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
54: aload_2
55: athrow
56: getstatic #16 // Field java/lang/System.out:Ljava/io/PrintStream;
59: ldc #45 // String In finally.
61: invokevirtual #24 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
64: return
Exception table:
from to target type
0 12 15 Class java/lang/ArithmeticException
0 34 45 any
From the byte code, we know that :
- the line 5 of source code corresponds to 8 – 11 of byte code, where an arithmetic exception will be throwed;
- in the exception table, the first exception handler indicates that if from 0 to 12, there is arithmetic exception, it will go to 15;
- then a number format exception will be throwed at line 8 of source code, which corresponds to line 26 of byte code;
- in the exception table, the second exception handler indicates that if from 0 to 34, there is any type of exception, it will go to 45;
- from line 45 to 51 of byte code, it corresponds to the finally block in source code;
- in the end, at 55 of byte code, the number format exception will be throwed out of main method.
4.3 Example of try-finally
Now in below code snippet, the only difference comparing to the previous one consists of the switch of throwed exceptions in try and catch blocks.
The execution flow of this code snippet is below :
- at line 4 : print “In Try” in console;
- at line 5 : can not parse space into integer, so need to throw number format exception, since catch block only focus on arithmetic exception, so it will go directly into finally block;
- at line 11 : print “In Finally” in console;
- at line 13 : throw number format exception of line 5.
1public class ExceptionTest18 {
2 public static void main(String[] args) {
3 try {
4 System.out.println("In Try.");
5 Integer.parseInt(" ");
6 } catch (ArithmeticException e) {
7 System.out.println("In Catch.");
8 int x = 1 / 0;
9 e.printStackTrace();
10 } finally {
11 System.out.println("In finally.");
12 }
13 }
14}
Below is the output of above code snippet :
In Try.
In finally.
Exception in thread "main" java.lang.NumberFormatException: For input string: " "
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
at java.base/java.lang.Integer.parseInt(Integer.java:648)
at java.base/java.lang.Integer.parseInt(Integer.java:778)
at ExceptionTest18.main(ExceptionTest18.java:5)
Below is the byte code of this code snippet :
public class ExceptionTest18 {
public ExceptionTest18();
Code:
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #16 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #22 // String In Try.
5: invokevirtual #24 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: ldc #30 // String
10: invokestatic #32 // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
13: pop
14: goto 56
17: astore_1
18: getstatic #16 // Field java/lang/System.out:Ljava/io/PrintStream;
21: ldc #38 // String In Catch.
23: invokevirtual #24 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
26: iconst_1
27: iconst_0
28: idiv
29: istore_2
30: aload_1
31: invokevirtual #40 // Method java/lang/ArithmeticException.printStackTrace:()V
34: getstatic #16 // Field java/lang/System.out:Ljava/io/PrintStream;
37: ldc #45 // String In finally.
39: invokevirtual #24 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
42: goto 64
45: astore_3
46: getstatic #16 // Field java/lang/System.out:Ljava/io/PrintStream;
49: ldc #45 // String In finally.
51: invokevirtual #24 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
54: aload_3
55: athrow
56: getstatic #16 // Field java/lang/System.out:Ljava/io/PrintStream;
59: ldc #45 // String In finally.
61: invokevirtual #24 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
64: return
Exception table:
from to target type
0 14 17 Class java/lang/ArithmeticException
0 34 45 any
}
From the above byte code, we know that :
- the line 5 of source code corresponds to line 10 of the byte code, where a number format exception will be throwed;
- in the exception table, the first exception handler only take care of arithmetic exception, so skip;
- the second exception handler indicates that if from 0 to 34, there is any type of exception, it will go to 45, which fits the situation;
- from 46 to 51, it corresponds to the finally block;
- in the end, at 55, the number format exception will be throwed out of main method.