java exception system

1 abnormal inheritance architecture

16301c82ebcc2b92.jpeg

  • The Throwable class is a superclass for all errors or exceptions in the Java language.
  • Only when the object is an instance of this class (or one of its subclasses), it can be thrown through the Java virtual machine or Java throw statement. Similarly, only this class or one of its subclasses can be a parameter type in a catch clause.
  • Throwable contains a snapshot of the thread execution stack when its thread is created. It also contains a message string that gives more information about the error.
  • Finally, it can also contain cause: another throwable that causes this throwable to be thrown. This cause facility first appeared in version 1.4. It is also called exception chain facility, because cause itself will have cause, and so on, forming an exception chain. Each exception is caused by another exception.

1.1 Error

  • Error is a subclass of Throwable that indicates serious problems that a reasonable application should not attempt to catch.
  • Most of these errors are exception conditions. Although ThreadDeath Error is a "normal" condition, it is also a subclass of Error because most applications should not try to catch it.
  • During the execution of this method, there is no need to declare any subclasses of errors that may be thrown but failed to be caught in its throws clause, because these errors may be exception conditions that will never happen again.
  • Java programs usually do not catch errors. Errors usually occur in the case of serious failures, which are outside the scope of Java program processing.

1.2 Exception

  • Exception s are mainly divided into two categories

    • One is "checked exception"
    • The other is RuntimeException (runtime exception), which is called "non checked exception".
  • Checked exceptions refer to those exceptions that the compiler requires to be handled during compilation. You must handle them during compilation.

1.2.1 common non inspection abnormalities:

Download png

1.2.2 common inspection abnormalities:

Download png

2. Custom exception type

All exceptions defined in Java's exception mechanism cannot foresee all possible errors. In some specific situations, we need to customize the exception type to report some error information upward.

  • In Java, you can customize exceptions. When writing your own exception class, you need to keep the following points in mind.
    • All exceptions must be subclasses of Throwable.
    • If you want to write a checking Exception class, you need to inherit the Exception class.
    • If you want to write a runtime exception class, you need to inherit the RuntimeException class.

3. Handling of exceptions

3.1 try...catch keyword

  • Use the try and catch keywords to catch exceptions.
  • try/catch code blocks are placed where exceptions can occur.

The code in the try/catch code block is called protection code. The syntax of using try/catch is as follows:

try {
   // Program code
} catch(ExceptionName e1) {
   //Catch block
}
  • The catch statement contains a declaration of the type of exception to catch. When an exception occurs in the protection code block, the catch block after try will be checked. If the exception is contained in the catch block, the exception will be passed to the catch block, which is the same as passing a parameter to the method.
  • The case where a try code block is followed by multiple catch code blocks is called multiple capture.
  • The syntax of multiple capture blocks is as follows:
try{
   // Program code
}catch(Variable name of exception type 1){
  // Program code
}catch(Variable name of exception type 2){
  // Program code
}catch(Variable name of exception type 2){
  // Program code
}

3.2 throws/throw keyword

  • If a method does not catch a checking exception, the method must be declared using the throws keyword. The throws keyword is placed at the end of the method signature. You can also throw an exception using the throw keyword, whether it is newly instantiated or just caught.
  • The declaration of the following method throws a RemoteException exception:
public class className {
  public void deposit(double amount) throws RemoteException {
    // Method implementation
    throw new RemoteException();
  }
  //Remainder of class definition
}

A method can declare to throw multiple exceptions, which are separated by commas.

3.3 finally keyword

  • finally keyword is used to create a code block that executes after a try code block.
  • Whether or not an exception occurs, the code in the finally code block will always be executed. In the finally code block, you can run closing statements such as cleaning types.
  • finally, the code block appears at the end of the catch code block. The syntax is as follows:
try{
  // Program code
}catch(Variable name of exception type 1){
  // Program code
}catch(Variable name of exception type 2){
  // Program code
}finally{
  // Program code
}

4. Execution sequence of try catch finally

The questions related to the execution sequence of try catch finally can be said to be "frequent visitors" in various interviews, especially when there is a return statement in the finally block. Let's look directly at several interview questions:

4.1 interview question 1:

public static void main(String[] args){
    int result = test1();
    System.out.println(result);
}

public static int test1(){
    int i = 1;
    try{
        i++;
        System.out.println("try block, i = "+i);
    }catch(Exception e){
        i--;
        System.out.println("catch block i = "+i);
    }finally{
        i = 10;
        System.out.println("finally block i = "+i);
    }
    return i;
}

The output results are as follows:

try block, i = 2
finally block i = 10
10

This is a fairly simple problem. There is no pit. Let's change it a little:

public static int test2(){
    int i = 1;
    try{
        i++;
        throw new Exception();
    }catch(Exception e){
        i--;
        System.out.println("catch block i = "+i);
    }finally{
        i = 10;
        System.out.println("finally block i = "+i);
    }
    return i;
}

The output results are as follows:

catch block i = 1
finally block i = 10
10

4.2 interview question 2

public static void main(String[] args){
    int result = test3();
    System.out.println(result);
}

public static int test3(){
    //The overall execution order when there is a return statement in the try statement block
    int i = 1;
    try{
        i++;
        System.out.println("try block, i = "+i);
        return i;
    }catch(Exception e){
        i ++;
        System.out.println("catch block i = "+i);
        return i;
    }finally{
        i = 10;
        System.out.println("finally block i = "+i);
    }
}

The output results are as follows:

try block, i = 2
finally block i = 10
2

Are you a little confused? Obviously, I have a return statement in the try statement block, but why did I finally execute the code in the finally block?

Let's decompile this class and see the implementation of bytecode compiled by test3 method:

0: iconst_1         //Load 1 into operand stack
1: istore_0         //Save the element at position 0 of the operand stack into the local variable table
2: iinc          0, 1   //Directly add one (i=2) to the element at position 0 of the local variable table
5: getstatic     #3 / / println method executed in line 5-27                
8: new           #5                  
11: dup
12: invokespecial #6                                                     
15: ldc           #7 
17: invokevirtual #8                                                     
20: iload_0         
21: invokevirtual #9                                                     24: invokevirtual #10                
27: invokevirtual #11                 
30: iload_0         //Load the element at position 0 of the local variable table into the operation stack (2)
31: istore_1        //Store the elements at the top of the operation stack in position 1 of the local variable table
32: bipush        10 //Load a constant into the operation stack (10)
34: istore_0        //Store 10 in local variable table 0
35: getstatic     #3 / / lines 35-57 execute the println method in finally             
38: new           #5                  
41: dup
42: invokespecial #6                  
45: ldc           #12                 
47: invokevirtual #8                  
50: iload_0
51: invokevirtual #9                
54: invokevirtual #10                 
57: invokevirtual #11                 
60: iload_1         //Load the element at the position of local variable table 1 into the operation stack (2)
61: ireturn         //Return the operation stack top element (2)
-------------------try + finally end ------------
------------------Here is catch + finally,allied ------------
62: astore_1
63: iinc          0, 1
.......
.......
  • From our analysis, we can see that the contents in the finally code block will always be executed. No matter whether the program is abnormal or not, the compiler will copy the code in the finally block in two copies and add them after try and catch respectively.

Some people may wonder that our i was originally stored in the position of local variable table 0, and the code in finally did fill the position of slot 0 with the value of 10, but why did the program still return the value of 2?

  • Looking at the bytecode carefully, you will find that before the return statement returns, the virtual opportunity pushes the value to be returned into the operand stack and waits for the return. Even if the finally statement block modifies i, the value to be returned does exist in the operand stack, so it will not affect the return result of the program.

4.3 interview question 3

public static int test4(){
    //There is a return statement in the finally statement block
    int i = 1;
    try{
        i++;
        System.out.println("try block, i = "+i);
        return i;
    }catch(Exception e){
        i++;
        System.out.println("catch block i = "+i);
        return i;
    }finally{
        i++;
        System.out.println("finally block i = "+i);
        return i;
    }
}

Operation results:

try block, i = 2
finally block i = 3
3

In fact, you can see the whole process from its bytecode instructions, not just its execution process.

 

16301c82ee79b8d0.png

You will find that the program will eventually return with the return statement in the finally code block, and directly ignore the return instruction in the try statement block.

Finally, there is an unwritten agreement on the use of exceptions: try to handle them uniformly in a centralized location, and don't use try catch everywhere, otherwise the code structure will be chaotic.


Author: love of Kailing
Link: https://www.jianshu.com/p/49d2c3975c56
Source: Jianshu
The copyright belongs to the author. For commercial reprint, please contact the author for authorization. For non-commercial reprint, please indicate the source.

Tags: Java

Posted by Jaehoon on Fri, 06 May 2022 09:28:30 +0300