JDK source code -- try catch finally exception

Keywords: JDK

abstract

The exception and exception handling mechanism in java will be explained in detail. Exception is a tool commonly used in development and a means to deal with program exceptions. This paper will introduce in detail the principle of using try catch in JDK to deal with exceptions.

Exception type

An unexpected event that occurs when a program is running, which prevents the program from executing normally as expected by the programmer, which is an Exception. All abnormal classes in Java inherit from the throwable class. Throwable mainly includes two categories: Error and Exception;

  • Error: the instance of the error class and its subclasses represents the error of the JVM itself. Including virtual machine errors and thread deadlocks. Once an error occurs, the program will completely hang up, which is called program terminator; For example, JVM memory overflows. Generally, programs do not recover from errors.
  • Exception: exception and its subclasses represent various unexpected events that occur when the program runs. It can be used by Java exception handling mechanism and is the core of exception handling. Exceptions mainly include two categories: non check exceptions (runtimeexceptions) and check exceptions (other exceptions)

  Unchecked exception: Error and RuntimeException and their subclasses. javac will not prompt and find such exceptions when compiling, and it is not required to handle these exceptions in the program. So if you like, we can write code to handle such exceptions (using try... catch... finally) or not. For these exceptions, we should fix the code instead of handling them through the exception handler. Most of the reasons for such exceptions are code writing problems. For example, in addition to 0 Error ArithmeticException, wrong forced type conversion Error ClassCastException, array index out of bounds ArrayIndexOutOfBoundsException, null object NullPointerException, etc.

checked exception: other exceptions except Error and RuntimeException. javac forces programmers to prepare for such exceptions (using try... Catch... finally or throws). In the method, either capture it with a try catch statement and process it, or throw it with a throw clause declaration, otherwise the compilation will not pass. Such exceptions are generally caused by the running environment of the program. Because the program may be run in various unknown environments, and the programmer cannot interfere with how the user uses the program written by him, the programmer should be prepared for such exceptions. Such as sqlexception, IOException, classnotfoundexception, etc.

Catch exception

(1) Try block: it is responsible for catching exceptions. Once exceptions are found in try, the control of the program will be transferred to the exception handler in catch block. [try statement block cannot exist independently, but must be stored with catch or finally block]

(2) Catch block: how to handle it? For example, issue warnings: prompt, check configuration, network connection, record errors, etc. After executing the catch block, the program jumps out of the catch block and continues to execute the following code. [precautions for writing catch blocks: exception classes handled by multiple catch blocks should be handled in the way of first catch subclasses and then catch parent classes, because exceptions will be handled nearby (from top to bottom).]

(3) Finally: the code that is finally executed to close and release resources.

One time exception capture

try
{
   //Some exceptions that will be thrown
}catch(ExceptionName e1){
   //The code block that handles the exception
}finally{
   //Final code to execute
}

In java, the task of exception handling is to transfer the execution control flow from the place where the exception occurs to the place where the exception can be handled. In other words, when an exception occurs in a statement of a function, the statement behind the statement will not be executed, and it loses focus. The execution flow jumps to the nearest matching exception handling catch code block for execution. After the exception is handled, the execution flow will then execute after "the catch code block that handled this exception".

Multiple exception capture

The case where a try code block is followed by multiple catch code blocks is called multiple capture.

try
{
   //Some exceptions that will be thrown
}catch(ExceptionName e1){
   //The code block that handles the exception
}catch(ExceptionName e2){
   //The code block that handles the exception
}catch(ExceptionName e3){
   //The code block that handles the exception
}catch(ExceptionName e4){
   //The code block that handles the exception
}finally{
   //Final code to execute
}

If an exception occurs in the protection code, the exception is thrown to the first catch block.

If the data type of the exception thrown matches ExceptionType1, it will be caught here.

If it does not match, it is passed to the second catch block.

This is done until the exception is caught or passed through all catch blocks.

Multiple exception handling code block order: subclass first and then parent class (if the order is wrong, the compiler will remind the error), and finally statement block handles the code to be executed finally.

throw and throws keywords

Exception throwing in java is usually implemented using the throw and throw keywords.

Throw --- throw the generated exception

Is an action that throws an exception. If you do not use the try catch statement to try to catch this exception, or add a declaration and throw the exception to the caller at a higher level for processing, the program will stop here and will not execute the remaining code. It is generally used for programmers to actively throw certain types of exceptions when some logic appears in the program.

public static void main(String[] args) { 
    String s = "abc"; 
    if(s.equals("abc")) { 
      throw new NumberFormatException(); 
    } else { 
      System.out.println(s); 
    } 
    //function(); 
}

Operation results:

Exception in thread "main" java.lang.NumberFormatException
at test.ExceptionTest.main(ExceptionTest.java:67)

throws function declaration

throws ---- declare what type of exception (Declaration) will be thrown. When a method may throw an exception, it is used to declare the exception that may be thrown, and then hand it to the upper layer method program that calls it for processing

public static void function() throws NumberFormatException{ 
    String s = "abc"; 
    System.out.println(Double.parseDouble(s)); 
  } 
    
  public static void main(String[] args) { 
    try { 
      function(); 
    } catch (NumberFormatException e) { 
      System.err.println("Non data types cannot be converted."); 
      //e.printStackTrace(); 
    } 
}

Comparison between throw and throws

1. throws appears in the method function header; throw appears in the body of the function.
2. Throws indicates a possibility of exceptions, which do not necessarily occur; Throw throws an exception. Executing throw must throw an exception object.
3. Both of them are negative exception handling methods (the negative here does not mean that this method is bad). They only throw or may throw exceptions, but the function will not handle exceptions. The real exception handling is handled by the upper layer call of the function.

void doA(int a) throws (Exception1,Exception2,Exception3){
      try{
         ......
 
      }catch(Exception1 e){
       throw e;
      }catch(Exception2 e){
       System.out.println("Something went wrong!");
      }
      if(a!=b)
       throw new Exception3("Custom exception");
}

1. Three exceptions (Exception1,Exception2,Exception3) may be generated in the code block.
2. If an Exception1 exception is generated, it will be caught and then thrown, which will be handled by the caller of the method.
3. If an Exception2 exception is generated, the method handles it by itself (that is, System.out.println("error!");). Therefore, this method will not throw exception 2 out, and void doa() throws exception 1 and exception 2 in exception 3 do not need to be written. Because it has been captured and processed with the try catch statement.
4.Exception3 exception is a logic error of the method, which is handled by the programmer himself. If exception exception3 is thrown in the case of this logic error, the caller of the method should also handle this exception. A custom exception is used here, which will be explained below.

Note: if a method calls a method that throws an exception, you must add a try catch statement to try to catch this exception, or add a declaration to throw the exception to a higher-level caller for processing

Custom exception

Why use custom exceptions and what are the benefits?

  • 1. When we are working, the project is developed by modules or functions. Basically, you will not develop the whole project alone. The use of user-defined exception classes unifies the way of external exception display.
  • 2. Sometimes when we encounter some verification or problems, we need to end the current request directly. At this time, we can end it by throwing a custom exception. If you use a newer version of spring MVC in your project, there is a controller enhancement, You can write a controller enhancement class through the @ ControllerAdvice annotation to intercept custom exceptions and respond to the corresponding information to the front end.
  • 3. Custom exceptions can be thrown when some special business logic in our project, such as "neutral". equals(sex). When gender is equal to neutral, we will throw exceptions, which will not exist in Java. Some errors in the system conform to Java syntax, but do not conform to the business logic of our project.

How to use custom exceptions?

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.
package com.zhuangxiaoyan.JDK;

public class MyException extends Exception {
     /**
     * Error code
     */
    private String errorCode;

    public MyException(){}
    
    /**
     * Construct a basic exception
     *
     * @param message
     *        Information description
     */
    public MyException(String message){
        super(message);
    }

    public String getErrorCode() {
        return errorCode;
    }

    public void setErrorCode(String errorCode) {
        this.errorCode = errorCode;
    }
}
package com.zhuangxiaoyan.JDK;

public class Main {
    public static void main(String[] args) {
      // TODO Auto-generated method stub
      String[] sexs = {"Male","female sex","neutral"};
      for(int i = 0; i < sexs.length; i++){
         if("neutral".equals(sexs[i])){
            try {
                throw new MyException("There is no neutral person!");
            } catch (MyException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
         }else{
             System.out.println(sexs[i]);
         }
       } 
    }
}

finally block and return

First of all, a fact that is not easy to understand: in the try block, even if there are return, break, continue and other statements that change the execution flow, finally will be executed.

public static void main(String[] args)
{
    int re = bar();
    System.out.println(re);
}
private static int bar() 
{
    try{
        return 5;
    } finally{
        System.out.println("finally");
    }
}
/*Output:
finally5
*/

In other words: try... catch... finally, all returns are executed as long as they can be executed. They all send to the same memory address (assuming that the address is 0) × 80) write the return value. The later executed data will overwrite the first executed data, and the return value taken by the caller is the last written value. Then, according to this idea, the following example is not difficult to understand.

Return in finally overrides the return value in try or catch.

public static void main(String[] args){
    int result;

    result  =  foo();
    System.out.println(result);     /2

    result = bar();
    System.out.println(result);    /2
}

@SuppressWarnings("finally")
public static int foo(){
    trz{
        int a = 5 / 0;
    } catch (Exception e){
        return 1;
    } finally{
        return 2;
    }

}

@SuppressWarnings("finally")
public static int bar(){
    try {
        return 1;
    }finally {
        return 2;
    }
}

return in finally suppresses (eliminates) the exceptions in the previous try or catch block

class TestException{
    public static void main(String[] args){
        int result;
        try{
            result = foo();
            System.out.println(result);           //Output 100
        } catch (Exception e){
            System.out.println(e.getMessage());    //No exceptions were caught
        }
 
        try{
            result  = bar();
            System.out.println(result);           //Output 100
        } catch (Exception e){
            System.out.println(e.getMessage());    //No exceptions were caught
        }
    }
 
    //Exceptions in catch are suppressed
    @SuppressWarnings("finally")
    public static int foo() throws Exception{
        try {
            int a = 5/0;
            return 1;
        }catch(ArithmeticException amExp) {
            throw new Exception("I will be ignored because of the following finally Used in return");
        }finally {
            return 100;
        }
    }
 
    //Exceptions in try are suppressed
    @SuppressWarnings("finally")
    public static int bar() throws Exception{
        try {
            int a = 5/0;
            return 1;
        }finally {
            return 100;
        }
    }
}

finally, the exceptions in the previous try or catch will be overwritten (eliminated)  

class TestException{
    public static void main(String[] args){
        int result;
        try{
            result = foo();
        } catch (Exception e){
            System.out.println(e.getMessage());    //Output: I am the Exception in final
        }
 
        try{
            result  = bar();
        } catch (Exception e){
            System.out.println(e.getMessage());    //Output: I am the Exception in final
        }
    }
 
    //Exceptions in catch are suppressed
    @SuppressWarnings("finally")
    public static int foo() throws Exception{
        try {
            int a = 5/0;
            return 1;
        }catch(ArithmeticException amExp) {
            throw new Exception("I will be ignored because of the following finally A new exception was thrown in");
        }finally {
            throw new Exception("I am finaly Medium Exception");
        }
    }
 
    //Exceptions in try are suppressed
    @SuppressWarnings("finally")
    public static int bar() throws Exception{
        try {
            int a = 5/0;
            return 1;
        }finally {
            throw new Exception("I am finaly Medium Exception");
        }
    }
}

The above three examples are different from ordinary people's coding thinking, so I suggest:

  • Don't use return in fianlly.
  • Don't throw an exception in finally.
  • Lighten the task of finally. Don't do anything else in finally. Finally blocks are most appropriate only to release resources.
  • Try to write all return s at the end of the function instead of try... catch... finally.

Use of Spring exception handler

Usually, when a web program is running, there are a lot of exceptions to deal with due to improper operation of users or bug s of the program. Some of these exceptions need to be exposed to users, such as login timeout, insufficient permissions and so on. You can tell the user what the error is by popping up a prompt message. This means that a mechanism is needed in the program to handle these exceptions and convert the program exceptions into user-readable exceptions. And the most important thing is to unify this mechanism and provide unified exception handling.

Global exception handling using enhanced Controller

@ExceptionHandler annotation. When @ ExceptionHandler is added to a method in a Controller, exceptions not captured in other methods of the Controller will be passed into the method annotated with @ ExceptionHandler in the form of parameters. First, you need to design a custom exception class for your system to pass the status code.

/** Created by xjl.
 * Custom exception
 */
public class SystemException extends RuntimeException{
    private String code;//Status code
    public SystemException(String message, String code) {
        super(message);
        this.code = code;
    }
    public String getCode() {
        return code;
    }
}

The so-called enhanced Controller is the @ ControllerAdvice annotation. Some annotations of the methods in the class with this annotation will be applied to all controllers, including the @ ExceptionHandler annotation. So you can write a global exception handling class:

/**
 * Created by xjl 2021/11/26.
 * Global exception handling, which captures all exceptions thrown in the Controller.
 */
@ControllerAdvice
public class GlobalExceptionHandler {
   //Handle custom exceptions
   @ExceptionHandler(SystemException.class) 
   @ResponseBody
   @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
   public Object customHandler(SystemException e){
      e.printStackTrace();
      return WebResult.buildResult().status(e.getCode()).msg(e.getMessage());
   }
   //Other unhandled exceptions
   @ExceptionHandler(Exception.class)
   @ResponseBody
   @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
   public Object exceptionHandler(Exception e){
      e.printStackTrace();
      return WebResult.buildResult().status(Config.FAIL).msg("System error");
   }
}

Only two exceptions are handled in this class, but most of the needs have been met. If there are still places that need special processing, you can add the processing methods. In this way, the methods in our current Controller can be very simple. For example, the logic for processing login can be written as follows:

/**
 * Created by xjl on 2021/11/26
 * account number
 */
@RestController
@RequestMapping("passport")
public class PassportController {
    PassportService passportService;
        @RequestMapping("login")
    public Object doLogin(HttpSession session, String username, String password){
        User user = passportService.doLogin(username, password);
        session.setAttribute("user", user);
        return WebResult.buildResult().redirectUrl("/student/index");
    }
}

In the doLogin method of passprotService, exceptions such as user name or password errors may be thrown, and then they will be handled by GlobalExceptionHandler to directly return exception information to the front end. Then the front end does not need to care whether exceptions are returned, because these have been defined.

The process in which an exception flows is:

For example, the doLogin method throws a custom exception with the code of FAIL and the message of user name or password error. Since this exception is not caught in the controller method, the exception will be thrown to the GlobalExceptionHandler, and then the GlobalExceptionHandler will return the status code and prompt information to the front end through WebResult. The front end will use the default processing function, The pop-up box prompts the user "wrong user name or password". For such an interaction, we don't need to write the logic of exception handling at all.

Blog reference

Posted by eneficus on Mon, 22 Nov 2021 18:28:28 -0800