Hi everyone, I’m developer FTD. Today we are going to talk about exception handling in the Java language.
The Java language was born in 1995, 26 years ago. As a relatively old language still has a strong vitality, Java in many aspects (such as high concurrency, portability, etc.) has obvious advantages, of course, in some aspects (such as image processing) also have shortcomings, today to introduce you to the exception is Java language provides a powerful, Mechanisms that allow us to properly respond to errors in our programs.
I. Introduction of exceptions
What is an exception?
Exceptions refer to abnormal events that occur during the running of a program due to external problems. The occurrence of exceptions often interrupts the running of the program. In Java, an object-oriented programming language, everything is an object, and the exception itself is also an object.
Classification of anomalies
When it comes to the classification of exceptions, it is impossible not to mention the inheritance structure of Java exceptions. As shown below:
As can be seen from the figure, exceptions are mainly composed of the following classes:
- Throwable
- Error
- Exception
Let’s take a look at each of these base classes.
Throwable
The Throwable class is the top-level parent of all errors or exceptions in the Java language, from which all other exception classes inherit. The Throwable class has two important subclasses: **Exception ** and Error, both important Java Exception handling subclasses, each containing a large number of subclasses.
An object can only be thrown by a Java Virtual machine or Java throw statement if it is an instance of this class or a subclass of it. Similarly, only this class or subclasses of it can be a parameter type in a catch clause.
The Throwable object contains a snapshot of the thread execution stack when its thread was created, as well as a message string that gives more information about the error.
Finally, it can also contain cause: another throwable that causes the throwable to throw. This cause facility first appeared in version 1.4. It’s also called an anomaly chain facility, because causes themselves have causes, and so on, and so forth, you have an anomaly chain, where each anomaly is caused by another anomaly.
Error
Error is a subclass of Throwable, and in general applications should not attempt to catch serious problems.
An Error is an Error that the program cannot handle and indicates a serious problem in running the application. Most errors have nothing to do with what the code writer is doing, and instead represent problems with the JVM (Java Virtual Machine) while the code is running.
For example, a Java Virtual Machine running error, an OutOfMemoryError occurs when the JVM no longer has the memory resources needed to continue the operation. When these exceptions occur, the Java Virtual Machine (JVM) typically selects thread termination.
These errors indicate that the fault occurs on the VM itself or when the VM tries to execute an application, such as a Java Virtual Machine running error or a NoClassDefFoundError. These errors are not detectable because they are outside the control and processing capabilities of the application, and most of them are not allowed to occur while the program is running. Even if an error does occur, a properly designed application should not, by nature, attempt to handle the exception it raises. In Java, errors are described by subclasses of Error.
Exception
Exception, and its subclasses, represent various unexpected events sent while the program is running. Can be used by the Java exception handling mechanism, is the core of exception handling.
Exceptions fall into two main categories:
1. Non-checking exceptions (unchecked)
Error and RuntimeException and their subclasses. The Java language does not prompt or detect such exceptions at compile time and does not require them to be handled in the program. So we can write code in our program to handle (using try… The catch… Finally), can also do nothing. These errors or exceptions should be fixed in the code rather than handled by an exception handler. Such exceptions occur mostly because of a problem with our code logic.
Such as:
-
When the program divides a number by 0, it throws the ArithmeticException exception;
-
During type casting, a bad cast throws a ClassCastException;
-
When using a collection when the array index cross-border will be thrown ArrayIndexOutOfBoundsException exception;
-
NullPointerException is thrown when an application uses a null object.
Common non-examining abnormalities are:
abnormal | describe |
---|---|
ArithmeticException | Throws an exception when an exception operation condition occurs. For example, an instance of this class is thrown when an integer is “divided by zero”. |
ArrayIndexOutOfBoundsException | An exception thrown when accessing an array with an invalid index. If the index is negative or greater than or equal to the array size, it is an invalid index. |
ArrayStoreException | An exception thrown when attempting to store an object of the wrong type into an array of objects. |
ClassCastException | An exception thrown when attempting to cast an object to an instance that is not of the same type or a subclass of it. |
IllegalArgumentException | Thrown when an invalid or incorrect argument is passed to a method. |
IllegalMonitorStateException | Raised when a thread has tried to wait for an object’s monitor, or notifies other threads that are waiting for the object’s monitor, and the thread itself does not get the specified monitor. |
IllegalStateException | A signal generated when a method is called at an illegal or inappropriate time. Or the Java environment or application is not in the proper state required by the requested operation. |
IllegalThreadStateException | Throws this exception when the thread is not in the proper state required by the requested operation. |
IndexOutOfBoundsException | An exception thrown when the index of a sort is out of range, for example, the sort of an array, string, or vector, etc. |
NegativeArraySizeException | Throw this exception if an application tries to create an array of negative size. |
NullPointerException | This exception is thrown when the application obtains a null object instance when it needs to manipulate an object. |
NumberFormatException | This exception is thrown when an application tries to convert a string to a numeric type, but the string cannot be converted to the proper format. |
SecurityException | An exception thrown by the security manager indicating a security violation. |
StringIndexOutOfBoundsException | This exception is thrown by the String method, indicating that the index is negative or exceeds the size of the String. |
2. Checked exceptions
Exceptions other than Error and RuntimeException. The Java language forces the programmer to do preparatory work for such exceptions (using try… The catch… Finally or throws). The compilation fails if it is either caught and processed in a try-catch statement or thrown with a throws clause declaration in a method. Such exceptions are usually caused by the environment in which the program is running. Because programs can be run in all kinds of unknown environments, and the programmer has no way of interfering with how the user uses the program, the programmer should always be prepared for such exceptions. Such as SQLException, IOException, ClassNotFoundException, etc.
Checking exceptions are exceptions that the compiler says must be handled at compile time, and you have to handle them at compile time.
Common diagnostic abnormalities are:
abnormal | describe |
---|---|
ClassNotFoundException | This exception is thrown when an application tries to load a class and finds no definition of the class by name. |
CloneNotSupportedException | Throw this exception when you clone an object that does not implement the Cloneable interface. |
IllegalAccessException | This exception is thrown when an application cannot access the definition of a class, member variable, or method when it attempts to access the class, member variable, or method by reflection. |
InstantiationException | Throw this exception when an attempt is made to create an instance of a Class using the newInstance method of a Class whose object cannot be instantiated because it is an interface or abstract Class. |
InterruptedException | Raised when a thread is interrupted by another thread. |
NoSuchFieldException | Throws this exception when the specified variable field is not found, |
NoSuchMethodException | Throws this exception when the specified class method cannot be found. |
Two, the first recognition of abnormalities
Below we pass a simple example, let everybody more intuitive understanding Java exception.
The following code throws the famous NullPointerException.
public class Test {
private int a = 1;
private int b = 2;
public static void main(String[] args) {
Test t1 = new Test();
Test t2 = null;
System.out.println(t1.a);
System.out.println(t2.a);
System.out.println(t2.c());
}
public String c(a) {
return "Wechat official account: I am DEVELOPER FTD"; }}Copy the code
Run the program, the console output is as follows:
1
Exception in thread "main" java.lang.NullPointerException
at cc.devclub.ftd.Test.main(Test.java:11)
Process finished with exit code 1
Copy the code
From the console output as you can see, the program to print the “1”, and then raise the Java program line 11 position. Lang. NullPointerException, then the program terminates.
3. Exception handling mechanism
When writing code to handle exceptions, there are two different ways to handle checking exceptions:
- Using a try… The catch… Finally… Block processing
- Use the throws/throw keyword in a method to hand the exception to the method caller
try… catch… Finally… The keyword
- Use the try and catch keywords to catch exceptions.
- Try /catch blocks are placed where exceptions can occur.
The code in a try/catch block is called protected code, and the syntax for using try/catch is as follows:
try{... }catch (IOException ioException) {
...
} catch (Exception exception) {
...
} finally{... }Copy the code
Try block:
- Put code in the try block where an exception might occur.
- If the try completes without an exception, then the code in the finally block and the code after finally, if any, is executed.
- If an exception occurs, the program tries to match the corresponding catch block.
Catch block:
- Each catch block is used to catch and handle a particular exception, or a subclass of that exception type. In Java7, you can declare multiple exceptions in a catch.
- The parentheses after catch define the exception type and the exception parameters. If the exception matches and is matched first, the virtual machine will use the catch block to handle the exception.
- You can use the exception parameters of a catch block to retrieve information about the exception. Exception parameters are local variables in the catch block and cannot be accessed by other blocks.
- If the exception that occurred in the current try block is not caught in any subsequent catch, finally is executed first and then external callers of the method are matched to the exception handler.
- If no exception occurs in the try, all catch blocks are ignored.
Something to watch out for
1. Local variables in try blocks, local variables in catch blocks (including exception variables), and local variables in finally may not be shared.
2. Each catch block is used to handle an exception. Exception matching is found from the top down in the order of the catch blocks, and only the first matching catch is executed. When matching, not only does exact matching run, but parent matching is also supported. Therefore, if multiple catch types under the same try block have a parent-child relationship, you should put the subclass exception first and the parent exception last to ensure that each catch block has a meaning.
3. In Java, the task of exception handling is to move the flow of execution control from where an exception occurs to where it can be handled. That is, when a statement of a method fails, the statement that follows it does not execute, and it loses focus. The flow of execution jumps to the nearest matching exception handling catch block. Once the exception is handled, the flow of execution continues after the catch block that handled the exception.
Finally block:
-
A finally block is not required and is usually optional.
-
The code in finally executes whether or not an exception occurs and whether or not an exception match is handled.
-
A try must have at least one catch block, otherwise, at least one finally block. But finally is not used to handle exceptions. Finally does not catch and handle exceptions. Exceptions can only be handled by catch blocks.
-
Finally does some cleanup work, such as closing streams, closing database connections, etc.
-
The finally block does not care if an exception occurs; if the corresponding try executes, it must also execute. There is only one way for a finally block not to execute: system.exit ().
A good programming practice is to open resources ina try block and clean them up and release them ina finally block to avoid memory leaks.
Points to note:
1, In the same try… The catch… Finally… Block. If an exception is thrown ina try and there is a matching catch block, the catch block is executed first, then the finally block is executed. If there is no catch block match, then finally is executed and the upper-level caller is searched for the appropriate catch block.
2, In the same try… The catch… Finally… Block if an exception occurs ina try and an exception is thrown ina matching catch block, then finally is executed: first the finally block is executed, and then the upper-level caller looks for the appropriate catch block.
Throws/throw keywords
- Throws keyword
If the code inside a method throws checked exceptions and the method itself does not fully handle them, the Java compiler requires that you declare these possible exceptions on the method signature using the throws keyword, or the compiler fails.
Throws is another way of handling exceptions, which is different from try… The catch… Finally… Throws exceptions that may occur in a method to the caller, but does not process them.
The reason for this exception handling may be that the method itself does not know how to handle such an exception, or that it is better handled by the caller, who is responsible for any exceptions that may occur.
- Throw a keyword
We can also explicitly throw an exception manually by using a throw statement, which must be followed by an exception object. The syntax is as follows:
throw exceptionObject
The throw statement must be written in the method, and the place where the throw statement is executed is an exception throw point, which is no different from the exception throw point automatically formed by the JRE.
public void save(User user) {
if (user == null)
throw new IllegalArgumentException("User object is empty");
/ /...
}
Copy the code
Try-catch-finally execution order
Try-catch-finally execution order is a familiar question in any interview, especially if the try-catch-finally block contains a return statement. Let’s go straight to a few interview questions:
Interview question 1:
public static void main(String[] args) {
int result = test1();
System.out.println(result);
}
public static int test1(a) {
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;
}
Copy the code
You might want to calculate what the programmer ends up doing.
The following output is displayed:
try block, i = 2
finally block i = 10
10
Copy the code
This is a fairly simple problem, no pits, let’s change it slightly:
public static int test2(a) {
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;
}
Copy the code
The following output is displayed:
catch block i = 1
finally block i = 10
10
Copy the code
The result is no surprise: the program throws an exception, which is then caught and processed by the method’s catch block.
Interview question 2:
public static void main(String[] args) {
int result = test3();
System.out.println(result);
}
public static int test3(a) {
// The overall execution order of a try block with a return statement
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); }}Copy the code
The following output is displayed:
try block, i = 2
finally block i = 10
2
Copy the code
Confused? Why did I execute the code in the finally block when I had a return statement in the try block?
Let’s decompile the class and look at the compiled bytecode implementation of the test3 method:
0: iconst_1 // add 1 to operand stack 1: istore_0 // store the element at position 0 of operand stack in local variable table 2: iinc 0, 1 // Add the element at position 0 of local variable table directly (I =2) 5: Getstatic #3 // line 5-27 println method 8: new #5 11: dup 12: Invokevirtual #6 15: LDC #7 17: Invokevirtual #8 20: Iload_0 21: invokevirtual #9 24: invokevirtual #10 27: invokevirtual #11 30: iloAD_0 Istore_1 // store the top element in the local variable table at position 1 32: bipush 10 // load a constant to the operation stack (10) 34: istore_0 // store 10 in the local variable table at position 0 35: Getstatic #3 // line 35-57 Execute finally println method 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 local variable table 1 into operation stack (2) 61: Ireturn / / will return to (2) the operation stack elements -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- try + finally end -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- here is the catch + finally, Similar -- -- -- -- -- -- -- -- -- -- -- -- 62, 63: astore_1 iinc 0, 1... .Copy the code
As you can see from our analysis, the reason the finally block is always executed, regardless of whether the program is exception or not, is that the compiler makes two copies of the finally block and adds them after the try and catch, respectively.
You might wonder why the program still returns a value of 2 when our I is stored in slot 0 and the code in finally does fill slot 0 with a value of 10.
If you look closely at the bytecode, you can see that the virtual machine pushes the value to be returned into the operand stack before the return statement returns. Even though the finally block modiates I, the value to be returned is already in the operand stack, so it does not affect the program’s return.
Interview question 3:
public static int test4(a) {
// Finally block has return statement
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);
returni; }}Copy the code
Running results:
try block, i = 2
finally block i = 3
3
Copy the code
Instead of memorizing its execution, you can see the process from its bytecode instructions.
You’ll notice that the program will eventually return using a return statement in the finally block and ignore the return instruction in the try block.
Custom exception
It is not possible for all exceptions defined in Java’s exception mechanism to anticipate all possible errors, and in certain situations, we need to define our own exception types to report up certain error messages.
Custom Exception types are fairly simple. You can choose to extend Throwable, Exception, or any of their subclasses, and you can even define an Exception type without implementing or overriding any of the parent classes’ methods.
Such as:
public class MyException extends RuntimeException{}Copy the code
public class MyException extends Exception{}Copy the code
By international convention, a custom exception should always contain the following constructor:
- A constructor with no arguments
- A constructor that takes a String argument and is passed to the constructor of the parent class.
- One that takes String and Throwable arguments and is passed to the parent constructor
- A constructor that takes a Throwable argument and is passed to the parent class’s constructor.
Here is the IOException class complete source code, we can refer to:
public class IOException extends Exception {
static final long serialVersionUID = 7818375828146090155L;
public IOException(a) {
super(a); }public IOException(String message) {
super(message);
}
public IOException(String message, Throwable cause) {
super(message, cause);
}
public IOException(Throwable cause) {
super(cause); }}Copy the code
Precautions for exceptions
1. When a subclass overrides a function with a throws declaration of the parent class, the exception declared by the subclass must be within the control of the parent class exception. The exception handler used to handle the parent class’s throws method must also apply to the subclass’s throws method. This is to support polymorphism.
For example, if a superclass method throws two exceptions, a subclass cannot throw three or more exceptions. The parent class throws IOException, and the subclass must throw IOException or a subclass of IOException.
2. Java programs can be multithreaded. Each thread is a separate flow of execution, a separate stack of function calls. If the program has only one thread, exceptions that are not handled by any code cause the program to terminate. If it is multithreaded, exceptions that are not handled by any code simply cause the thread in which the exception was created to terminate.
That is, exceptions in Java are thread-independent and should be handled by the thread itself, not delegated externally, and not directly affecting the execution of other threads.
Common errors with exception usage
1. Display the exception directly on the page or client
It is not uncommon for exceptions to be printed directly to the client. Once a program runs abnormally, the container by default prints the exception stack directly to the page. From the customer’s point of view, any exception has no practical significance, the vast majority of customers can not understand the abnormal information, software development should try to avoid the anomaly directly presented to the user, must be in the front display layer of the anomaly packaging after display. Currently, most applications are in the mode of front and back end separation. This direct print exception has been relatively improved, but we should pay special attention to this principle when coding.
2. Ignore exceptions
The following exception handling simply prints the exception to the console and has no meaning. And there is an exception that does not interrupt the program, which then calls the code to continue executing, leading to more exceptions.
public void retrieveObjectById(Long id) {
try {
/ /.. some code that throws SQLException
} catch (SQLException ex) {
/** * Anyone who knows knows that the exception print here is meaningless and simply prints the error stack to the console. * In a Production environment, the error stack needs to be printed to a log. * And the continuation of the program after the catch will cause further problems */ex.printStacktrace(); }}Copy the code
If an exception is caught, do not handle it. This is a big no-no when we write code.
public void retrieveObjectById(Long id) {
try {
/ /.. some code that throws SQLException
} catch (SQLException ex) {
throw new RuntimeException("The Exception in retieveObjectById", the ex); } finally { //clean up resultset, statement, connection etc } }Copy the code
3. Include the exception in the loop block
As shown in the code below, the exception is contained in the for loop block.
for (int i = 0; i < 100; i++) {
try{}catch (XXXException e) {
//....}}Copy the code
We all know that exception handling consumes system resources. At first glance, everyone thought they would not make such a mistake. To put it another way, class A executes A loop that calls A method of class B, but the method called in class B contains A try-catch block. Strip out the class hierarchy and the code looks exactly the same.
4. Catch all potential exceptions with Exception
A method execution throws several different types of exceptions. For code brevity, use the base class Exception to catch all potential exceptions, as shown in the following example:
public void retrieveObjectById(Long id) {
try {
/ /... A code call that throws IOException
/ /... A code call that throws an SQLException
} catch (Exception e) {
// All potential exceptions caught by the base Exception class are used here. If multiple levels are caught this way, valid information about the original Exception will be lost
throw new RuntimeException("The Exception in retieveObjectById", e); }}Copy the code
A top-level exception will catch all possible exceptions. This will ensure that the exception will be caught, but the program will not be able to handle different error exceptions properly.
public void retrieveObjectById(Long id) {
try {
/ /.. some code that throws RuntimeException, IOException, SQLException
} catch (IOException e) {
// Only IOException is caught
throw new RuntimeException(/* Specifies the error code for IOException */code, "The Exception in retieveObjectById", e); } catch (SQLException e) {// throw new RuntimeException(SQLException e);The Exception in retieveObjectById ", e); }}Copy the code
5. The information contained in the exception is insufficient to locate the problem
Exceptions should not only let developers know what went wrong, but more often, developers need to know what caused the problem. We know that java.lang. Exception has a constructor for a string type parameter that can be customized to be an easy-to-understand prompt.
With simple custom information developers can only know where an exception is occurring, but in many cases developers need to know what parameters are causing the exception. At this point we need to append the parameter information of the method call to the custom information. The following example lists only one parameter. In the case of multiple parameters, you can write a separate utility class to organize such strings.
public void retieveObjectById(Long id) {
try {
/ /.. some code that throws SQLException
} catch (SQLException ex) {
// Add parameter information to the exception information
throw new RuntimeException("Exception in retieveObjectById with Object Id :"+ id, ex); }}Copy the code
conclusion
Exceptions as an important error handling mechanism in Java language, but also as an important guarantee to find the cause of the program, improve the robustness of the program, and a good experience of front-end products, so it is very necessary to master the use of exceptions, I hope this article can help you, if you have any questions or problems welcome harassment at any time.
Writing is not easy, if you like this article, please like and forward, your attention is our motivation to continue to move forward
reference
- Error and experience summary of Java exception handling
Technical people, technical soul, liver a technical article every day, ヾ(◍°∇°◍) Blue ha ha ~
About the author
- GitHub:github.com/ForTheDevel…
- The Denver nuggets: juejin. Cn/user / 120472…
- CSDN:blog.csdn.net/ForTheDevel…
- Zhihu: www.zhihu.com/people/fort…
- Segmentfault:segmentfault.com/u/for_the_d…
Contact the author
-
Wechat id: ForTheDeveloper
-
Public account: ForTheDevelopers