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 :

  1. at line 4 : print “In Try” in console;
  2. at line 5 : divisor is 0, so throw an arithmetic exception, which leads to enter into the catch block;
  3. at line 7 : print “In Catch” in console;
  4. at line 8 : can not parse space into integer, so need to throw number format exception, but firstly enter into the finally block;
  5. at line 11 : print “In Finally” in console;
  6. 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 :

  1. at line 4 : print “In Try” in console;
  2. 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;
  3. at line 11 : print “In Finally” in console;
  4. 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.