Java exception system

The exception of Java is class. Its inheritance relationship is as follows:

                     ┌───────────┐
                     │  Object   │
                     └───────────┘
                           ▲
                           │
                     ┌───────────┐
                     │ Throwable │
                     └───────────┘
                           ▲
                 ┌─────────┴─────────┐
                 │                   │
           ┌───────────┐       ┌───────────┐
           │   Error   │       │ Exception │
           └───────────┘       └───────────┘
                 ▲                   ▲
         ┌───────┘              ┌────┴──────────┐
         │                      │               │
┌─────────────────┐    ┌─────────────────┐┌───────────┐
│OutOfMemoryError │... │RuntimeException ││IOException│...
└─────────────────┘    └─────────────────┘└───────────┘
                                ▲
                    ┌───────────┴─────────────┐
                    │                         │
     ┌─────────────────────┐ ┌─────────────────────────┐
     │NullPointerException │ │IllegalArgumentException │...
     └─────────────────────┘ └─────────────────────────┘

From the inheritance relationship, we can see that throwable is the root of the Exception system, which inherits from Object. Throwable has two systems: error and Exception. Error indicates a serious error, and the program is generally unable to do anything about it, for example:

  • OutOfMemoryError: out of memory
  • NoClassDefFoundError: a Class could not be loaded
  • StackOverflowError: stack overflow

An Exception is a runtime error that can be caught and processed.

Some exceptions are part of the application's logical handling and should be caught and handled. For example:

  • NumberFormatException: malformed numeric type
  • FileNotFoundException: file not found
  • SocketException: failed to read the network

There are also some exceptions caused by incorrect programming of program logic. The program itself should be repaired. For example:

  • NullPointerException: call a method or field on a null object
  • IndexOutOfBoundsException: array index out of bounds

Exception s fall into two categories:

  1. RuntimeException and its subclasses;
  2. Non RuntimeException (including IOException, reflective operationexception, etc.)

Java stipulates:

  • Exceptions that must be caught include Exception and its subclasses, but do not include RuntimeException and its subclasses. This type of Exception is called Checked Exception.
  • Exceptions that do not need to be caught include Error and its subclasses, RuntimeException and its subclasses.

Note: the compiler does not make mandatory capture requirements for RuntimeException and its subclasses, which does not mean that the application itself should not capture and process RuntimeException. Whether it needs to be captured, and analyze the specific problems.

Abnormal propagation

When a method throws an exception, if the current method does not catch the exception, the exception will be thrown to the upper layer to call the method until a try is encountered Until catch is captured:

public class Main {
    public static void main(String[] args) {
        try {
            process1();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    static void process1() {
        process2();
    }

    static void process2() {
        Integer.parseInt(null); // NumberFormatException will be thrown
    }
}

The method call stack can be printed out through printStackTrace(), similar to:

java.lang.NumberFormatException: null
    at java.base/java.lang.Integer.parseInt(Integer.java:614)
    at java.base/java.lang.Integer.parseInt(Integer.java:770)
    at Main.process2(Main.java:16)
    at Main.process1(Main.java:12)
    at Main.main(Main.java:5)

printStackTrace() is very useful for debugging errors. The above information indicates that NumberFormatException is in Java lang.Integer. From bottom to top, the call levels thrown in the parseInt method are:

  1. main() calls process1();
  2. process1() calls process2();
  3. process2() calls integer parseInt(String);
  4. Integer.parseInt(String) calls integer parseInt(String, int).

Conversion exception

public class Main {
    public static void main(String[] args) {
        try {
            process1();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    static void process1() {
        try {
            process2();
        } catch (NullPointerException e) {
            throw new IllegalArgumentException();
        }
    }

    static void process2() {
        throw new NullPointerException();
    }
}

The printed exception stack is similar to:

java.lang.IllegalArgumentException
    at Main.process1(Main.java:15)
    at Main.main(Main.java:5)

This indicates that the new exception has lost the original exception information, and we can't see the information of the original exception NullPointerException.

In order to trace the complete Exception stack, when constructing an Exception, pass in the original Exception instance, and the new Exception can hold the original Exception information. Improvements to the above code are as follows:

public class Main {
    public static void main(String[] args) {
        try {
            process1();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    static void process1() {
        try {
            process2();
        } catch (NullPointerException e) {
            throw new IllegalArgumentException(e);
        }
    }

    static void process2() {
        throw new NullPointerException();
    }
}

Run the above code and the printed exception stack is similar to:

java.lang.IllegalArgumentException: java.lang.NullPointerException
    at Main.process1(Main.java:15)
    at Main.main(Main.java:5)
Caused by: java.lang.NullPointerException
    at Main.process2(Main.java:20)
    at Main.process1(Main.java:13)

Note that Caused by: Xxx indicates that the captured IllegalArgumentException is not the root cause of the problem, but the NullPointerException, which is in main Thrown by the process2 () method.

To get the original exception in the code, you can use throwable Getcause() method. If null is returned, it indicates that it is already a "root exception".

With complete exception stack information, we can quickly locate and fix code problems.

When you catch an exception and throw it again, you must keep the original exception, otherwise it is difficult to locate the first crime scene!

Keywords: Java JavaSE

Added by kooks on Sat, 15 Jan 2022 06:30:22 +0200