[Java] Throwing an Exception in Exception Handling

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-level calling method until it encounters one that is try ... catchcaught:

// exception
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
    }
}

By printStackTrace()printing the call stack of the method, it is 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()It is very useful for debugging errors. The above information indicates that it was thrown in the method. From bottom to top, the calling level is as follows NumberFormatException:java.lang.Integer.parseInt

main()调用process1()process1()调用process2()process2()调用Integer.parseInt(String)Integer.parseInt(String)调用Integer.parseInt(String, int)

Looking at the source code of Integer.java, we can see that the code of the method that throws an exception is as follows:

public static int parseInt(String s, int radix) throws NumberFormatException {
    
    
    if (s == null) {
    
    
        throw new NumberFormatException("null");
    }
    ...
}

Moreover, each layer call gives the line number of the source code, which can be directly located.

Throwing exceptions
When an error occurs, for example, the user enters an illegal character, we can throw an exception.

How to throw an exception? Refer to Integer.parseInt()the method, throwing an exception in two steps:

Creates Exceptionan instance of a; throws
with throwstatement.
Below is an example:

void process2(String s) {
    
    
    if (s==null) {
    
    
        NullPointerException e = new NullPointerException();
        throw e;
    }
}
实际上,绝大部分抛出异常的代码都会合并写成一行:

void process2(String s) {
    
    
    if (s==null) {
    
    
        throw new NullPointerException();
    }
}

If a method catches an exception and throws a new exception in the catch clause, it is equivalent to "converting" the thrown exception type:

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

void process2(String s) {
    
    
    if (s==null) {
    
    
        throw new NullPointerException();
    }
}

When process2()thrown NullPointerException, process1()caught, then thrown IllegalArgumentException().

If main()caught in IllegalArgumentException, let's look at the printed exception stack:

// 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 shows that the new exception has lost the original exception information, and we can no longer see NullPointerExceptionthe information of the original exception.

In order to be able to trace the complete exception stack, when constructing an exception, the original Exception instance is passed in, and the new Exception can hold the original Exceptioninformation. Improvements to the above code are as follows:

// 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(e);
        }
    }

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

Running the above code, 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 Caused by: Xxxthat what is captured IllegalArgumentExceptionis not the root cause of the problem, the root cause is that it is thrown NullPointerExceptionin the method.Main.process2()

To get the original exception in code you can use Throwable.getCause()method. If it returns null, it means that it is already a "root exception".

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

When an exception is caught and thrown again, the original exception must be kept, otherwise it will be difficult to locate the first crime scene!
If we throw an exception in a try or catch block, will the finally statement execute? For example:

// exception
public class Main {
    
    
    public static void main(String[] args) {
    
    
        try {
    
    
            Integer.parseInt("abc");
        } catch (Exception e) {
    
    
            System.out.println("catched");
            throw new RuntimeException(e);
        } finally {
    
    
            System.out.println("finally");
        }
    }
}

The above code execution results are as follows:

catched
finally
Exception in thread "main" java.lang.RuntimeException: java.lang.NumberFormatException: For input string: "abc"
    at Main.main(Main.java:8)
Caused by: java.lang.NumberFormatException: For input string: "abc"
    at ...

The first line is printed catched, indicating that the statement block has been entered catch. The second line is printed finally, indicating that the sentence block is executed finally语.

Therefore, catchthrowing an exception in will not affect finallthe execution of y. JVMwill be executed first finally, and then an exception will be thrown.

Exception shielding
If an exception is thrown when the finally statement is executed, can the exception of the catch statement continue to be thrown? For example:


// exception
public class Main {
    
    
    public static void main(String[] args) {
    
    
        try {
    
    
            Integer.parseInt("abc");
        } catch (Exception e) {
    
    
            System.out.println("catched");
            throw new RuntimeException(e);
        } finally {
    
    
            System.out.println("finally");
            throw new IllegalArgumentException();
        }
    }
}

Execute the above code and find that the exception information is as follows:

catched
finally
Exception in thread "main" java.lang.IllegalArgumentException
    at Main.main(Main.java:11)

This shows that after finally throws an exception, the exception that was originally prepared to be thrown in the catch "disappears", because only one exception can be thrown. Exceptions that are not thrown are called "masked" exceptions (Suppressed Exception).

In rare cases, we need to know about all exceptions. How to save all exception information? The method is to first save the original exception with the origin variable, then call Throwable.addSuppressed(), add the original exception, and finally throw it in finally:

// exception
public class Main {
    
    
    public static void main(String[] args) throws Exception {
    
    
        Exception origin = null;
        try {
    
    
            System.out.println(Integer.parseInt("abc"));
        } catch (Exception e) {
    
    
            origin = e;
            throw e;
        } finally {
    
    
            Exception e = new IllegalArgumentException();
            if (origin != null) {
    
    
                e.addSuppressed(origin);
            }
            throw e;
        }
    }
}

When both catch and finally throw an exception, although the catch exception is shielded, the exception thrown by finally still includes it:

Exception in thread "main" java.lang.IllegalArgumentException
    at Main.main(Main.java:11)
Suppressed: java.lang.NumberFormatException: For input string: "abc"
    at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.base/java.lang.Integer.parseInt(Integer.java:652)
    at java.base/java.lang.Integer.parseInt(Integer.java:770)
    at Main.main(Main.java:6)

Throwable.getSuppressed()All n can be obtained by Suppressed Exceptio.

In most cases, do not throw exceptions in finally. Therefore, we usually don't need to care Suppressed Exception.

Posting exceptions when asking questions The
detailed stack information printed by exceptions is the key to finding out the problem. Many beginners only post codes when asking questions, but do not post exceptions.

Who taught you not to post exception stacks when asking questions

Some children's shoes only post some abnormal information, and the most important ones Caused by: xxxare omitted. This is an incorrect way of asking questions and needs to be changed.

summary

The call printStackTrace()can print the exception propagation stack, which is very useful for debugging;

When catching an exception and throwing a new exception again, the original exception information should be held;

Normally don't finallythrow exceptions in . If an exception is thrown in finally, the original exception should be added to the original exception. The caller can Throwable.getSuppressed()get all added by Suppressed Exception.

Guess you like

Origin blog.csdn.net/ihero/article/details/132165769