Java exception in-depth research and analysis, Java in-depth research and analysis
The content of this article belongs to the scope of basic knowledge research. Do not think that the exceptional knowledge can be mastered after reading this article. Remember: I am not familiar with source code reading, so it is difficult for you to know when to customize exceptions and when to throw exceptions.
Exception mechanism Overview
The exception mechanism refers to how the program handles errors. Specifically, the exception Mechanism provides a secure channel for program exit. When an error occurs, the execution process of the program changes, and the control of the program is transferred to the exception processor.
Exception Handling Process
When an exception is thrown in the program, the program jumps out of the Code that causes the exception in the program. The Java virtual machine detects catch blocks that match the try keyword to handle the exception. if an exception is found, the control is handed over to the Code in the catch block, and then the program continues to be executed. The code with exceptions in the try block will not be re-executed. If no catch block is found to handle the exception, the current thread is aborted when all finally block code is executed and the ThreadGroup uncaughtException method of the current thread is called.
Abnormal Structure
Exception inheritance structure: Throwable is the base class. Error and Exception inherit Throwable, RuntimeException, and IOException. Error, RuntimeException, and its subclass become unchecked, and other exceptions become checked ).
Error
Error indicates that the program encountered a very serious and unrecoverable Error during running. In this case, the application can only stop running, for example, an Error occurs on the JAVA Virtual Machine. An Error is an unchecked Exception. The Compiler does not check whether the Error is handled, and does not need to catch an Error type Exception in the program. Generally, an Error type exception should not be thrown in the program.
RuntimeException exception
Exception exceptions include RuntimeException exceptions and other non-RuntimeException exceptions. RuntimeException is an Unchecked Exception, which indicates that the compiler does not check whether the program processes RuntimeException, and does not need to capture RuntimException exceptions in the program, you do not have to throw the RuntimeException class in the method body declaration. When RuntimeException occurs, it indicates that a programming error occurs in the program. Therefore, you should find out the program to modify the error, instead of capturing RuntimeException.
Checked Exception
Checked Exception, which is also the most commonly used Exception in programming. All exceptions inherited from Exception and not RuntimeException are checked Exception, IOException and ClassNotFoundException in. The JAVA language requires that the checked Exception must be processed. The Compiler checks the checked Exception, declares that the checked Exception is thrown in the method body, or uses the catch statement to capture the checked Exception for processing. Otherwise, the checked Exception cannot be compiled.
An exception is thrown when the method is declared.
Syntax: throws (omitted)
Why should I throw an exception in the declaration method?
Whether a method throws an exception is as important as the type of the method return value. Assuming that the method throws an exception but does not declare that the method throws an exception, the client programmer
You can call this method without writing code to handle exceptions. In this case, once an exception occurs, no suitable exception controller can be used to solve the exception.
Why must I have checked the thrown exception? RuntimeException and Error can be generated in any code. They do not need to be thrown by the programmer. Once an Error occurs, the corresponding exception is automatically thrown. When an Error occurs, the programmer is generally powerless. When a RuntimeException occurs, the program must have a logic Error and must be modified. Only exceptions that have been checked are the concern of the programmer, the program should and should only throw or handle checked exceptions. The check exception is thrown by the programmer. There are two situations: the client programmer calls the library function that throws the exception, and the client programmer throws the exception by using the throw statement.
Note: The subclass method that overwrites a method of the parent class cannot throw more exceptions than the parent class method. Therefore, when designing a method of the parent class, an exception is declared and thrown, however, the Code of the actual implementation method does not throw an exception, so that the subclass method can throw an exception when overwriting the parent class method.
How to throw an exception in a method
Syntax: throw (Omitted) throws an exception?
For an exception object, the really useful information is the exception object type, and the exception object itself is meaningless. For example, if the type of an exception object is ClassCastException, this class name is the only useful information. Therefore, when selecting an exception to be thrown, the most important thing is to select the exception class name to clearly indicate the exception.
Exception objects usually have two types of constructor: one is a constructor without parameters, and the other is a constructor with a string, this string will be used as an additional description for this exception object except for the type name.
Why create your own exceptions?
When Java built-in exceptions cannot explicitly describe the exceptions, you need to create your own exceptions. It should be noted that the only useful information is the type name, so do not spend effort on the design of the exception class.
Difference between throw and throws
/*** Java learning and communication QQ group: 589809992 let's learn Java together! */Public class TestThrow {public static void main (String [] args) {try {// call the method with throws declaration. The exception must be explicitly caught. // otherwise, throwChecked (-3);} catch (Exception e) {System. out. println (e. getMessage ();} // call the method that throws a Runtime exception to explicitly capture the exception, // ignore the exception throwRuntime (3 );} public static void throwChecked (int a) throws Exception {if (a> 0) {// throw Exception on your own // The code must be in the try block, or throw new Exception ("a value greater than 0, not meeting the requirements");} public static void throwRuntime (int a) in a method with throws Declaration) {if (a> 0) {// throw a RuntimeException by yourself. This exception can be explicitly captured and ignored completely, send the exception to the method caller to handle throw new RuntimeException ("the value of a is greater than 0 and does not meet the requirements ");}}}
Additionally, the throwChecked function is written as follows:
Public static void throwChecked (int a) {if (a> 0) {// throw Exception on your own // The code must be in the try block, or in a method with throws declaration, try {throw new Exception ("the value of a is greater than 0 and does not meet the requirements");} catch (Exception e) {// TODO Auto-generated catch block e. printStackTrace ();}}}
Note: In this case, throwChecked in the main function does not need a try exception.
Should I throw an exception in the declaration method or catch an exception in the method?
Handling principle: capture and handle exceptions that know how to handle, and pass exceptions that do not know how to handle
Use finally blocks to release resources
The finally keyword ensures that the statements in finally are executed no matter how the program leaves the try block. In the following three cases, the finally block is entered:
(1) the code in the try block is successfully executed.
(2) throw an exception in the try block.
(3) execute return, break, and continue in the try block.
Therefore, when you need a place to execute the code that must be executed under any circumstances, you can put the code into the finally block. When your program uses external resources, such as database connections and files, you must write the code for releasing these resources to the finally block.
Note that the finally block cannot throw an exception. The JAVA exception handling mechanism ensures that the finally block must be executed in any case before the try block is left. Therefore, when an exception occurs in the try block, the Java virtual machine first forwards the code in the finally block to the finally block and then throws an exception after the finally block is executed. If an exception is thrown in the finally block, the exception captured by the try block cannot be thrown. The exception caught by the outside is the exception information in the finally block, the real exception stack information in the try block is lost. See the following code:
Connection con = null; try {con = dataSource. getConnection ();......} Catch (SQLException e ){...... Throw e; // after some processing, the database exception is thrown to the caller for processing} finally {try {con. close ();} catch (SQLException e) {e. printStackTrace ();......}}
After running the program, the caller obtains the following information:
Java. lang. NullPointerException
At myPackage. MyClass. method1 (methodl. java: 266)
Instead of the database exception we expected. This is because con is null. NullPointerException is thrown in the finally statement. Adding the finally block to determine whether con is null can avoid this situation.
Loss exception
See the following code:
Public void method2 () {try {...... Method1 (); // method1 performed Database Operations} catch (SQLException e ){...... Throw new MyException ("database exception occurred:" + e. getMessage) ;}} public void method3 () {try {method2 () ;}catch (MyException e) {e. printStackTrace ();......}}
In the above method2 code, after the try block captures the database exception SQLException thrown by method1, a new custom exception MyException is thrown. There is no problem with this code, but let's take a look at the console output:
MyException: a database exception occurs. The object name 'mytable' is invalid. At MyClass. method2 (MyClass. java: 232) at MyClass. method3 (MyClass. java: 255)
The original exception SQLException information is lost. Here we can only see the MyException stack defined in method2, but the stack of the database exception in method1 cannot be seen. How can we troubleshoot this problem, only one row of method1 code can be used to find database operation statements.
JDK developers are aware of this situation. In JDK1.4.1, two constructor methods are added for the Throwable class: public Throwable (Throwable cause) and public Throwable (String message, Throwable cause ), the original exception stack information passed in the constructor is printed in the printStackTrace method. However, programmers who are still using JDK1.3 can only print the original exception stack information by themselves. The implementation process is also very simple. You only need to add an original exception field to the custom exception class, input the original exception in the constructor, and then reload the printStackTrace method, first, call the printStackTrace method of the original exception saved in the class, and then call super. the printStackTrace method can print the original exception information. You can define the MyException class in the previous Code as follows:
Import java. io. printStream; import java. io. printWriter; public class MyException extends Exception {private static final long serialVersionUID = 1L; // original Exception private Throwable cause; // constructor public MyException (Throwable cause) {this. cause = cause;} public MyException (String s, Throwable cause) {super (s); this. cause = cause;} // reload the printStackTrace method to print out the original exception stack information public void printStackTrace () {if (cause ! = Null) {cause. printStackTrace ();} super. printStackTrace ();} public void printStackTrace (PrintStream s) {if (cause! = Null) {cause. printStackTrace (s);} super. printStackTrace (s);} public void printStackTrace (PrintWriter s) {if (cause! = Null) {cause. printStackTrace (s) ;}super. printStackTrace (s );}}