Author: Maverick
Blog:Http://blog.csdn.net/zhaohuabing reprinted please indicate the source
1 Introduction
Before the emergence of the Java language, traditional Exception Handling Methods mostly use return values to identify exceptions in programs. Although this method is familiar to programmers, it has many disadvantages. First, an API can return arbitrary return values. These return values do not explain whether the return value represents an exception or a specific exception, the program that needs to call the API determines and explains the meaning of the returned value. Second, there is no mechanism to ensure that exceptions will be handled. The caller can simply ignore the returned value. The API caller must remember to check the returned value and handle exceptions. This method also makes the program code obscure and lengthy. When I/O operations are performed and other operations that are prone to exceptions, you will find that most of the code is used to handle switch branches in abnormal situations, the program code is poorly readable.
As mentioned above, Java Exception Handling Mechanism provides a good solution. By throwing a JDK pre-defined or custom exception, it can indicate the exceptions in the program, and the Java language mechanism ensures that exceptions will be properly handled; reasonable Use of exception handling mechanisms will make the program code clear and easy to understand.
2. Java Exception Handling Mechanism
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.
3 Java exception class levels
Shows the Java exception class hierarchy:
Figure 1 Java exception class hierarchy
Throwable is the base class of all exceptions. Generally, throwable objects are not directly thrown in the program. Exception and error are subclasses of throwable. In exception, there are two types: runtimeexception and general exception. Java exceptions can be divided into three types:
The first type is error, which 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 capture an error type exception in the program. Generally, an error type exception should not be thrown in the program.
The second type is runtimeexception. runtimeexception is an unchecked exception, which indicates that the compiler does not check whether the program processes runtimeexception. in the program, you do not need to capture runtimexception exceptions, 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.
The third type is General 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 1. 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. Checked exception is used in the following semantic environment:
(1) This exception can be recovered. If an Internet connection is aborted, You can reconnect and perform subsequent operations.
(2) The program depends on unreliable external conditions, which may cause errors, such as system Io.
(3) This exception does not cause errors in program processing. After some processing, you can continue the subsequent operations.
4. Notes for Java Exception Handling
The rational use of the Java exception mechanism can make the program robust and clear, but unfortunately, the Java exception handling mechanism is often used incorrectly. The following are some notes about exceptions:
1. Do not ignore checked exception
See the following code:
Try
{
Method1 (); // Method1 throws exceptiona
}
Catch (effectiona E)
{
E. printstacktrace ();
}
The above Code does not seem to have any problem. After an exception is caught, the exception is printed and then executed. In fact, exceptions occur in catch blocks without any processing (print exceptions cannot be considered as handling exceptions because debugging information is useless after the program is delivered and run ). In this way, although the program can continue to be executed, because the operation here has encountered an exception, it will cause future operations to fail to develop as expected, and may lead to two results:
First, this exception causes an exception to be thrown elsewhere in the program. This situation can confuse programmers during debugging, because the place where new exceptions are thrown is not the place where the program actually fails, nor the real cause of the problem;
The other is that the program continues to run and produces an incorrect output result, which is more difficult to capture, because it is likely to be regarded as a correct output.
So what should we do? Here we have four options:
(1) handle exceptions and fix them so that the program can continue to run.
(2) re-throw an exception. After analyzing the exception, it is found that the exception cannot be handled here. Then, re-Throw the exception and ask the caller to handle it.
(3) convert an exception to a custom exception that you can understand and then throw it. Do not lose the original exception information (see figure 5 ).
(4) do not capture exceptions.
Therefore, when an unchecked exception is captured, the exception must be handled. If you think it is unnecessary to handle the exception here, do not capture the exception and declare the exception in the method body, the upper-layer caller can handle this exception.
2. Do not capture all exceptions at once
See the following code:
Try
{
Method1 (); // Method1 throws exceptiona
Method2 (); // Method1 throws predictionb
Method3 (); // Method1 throws exceptionc
}
Catch (exception E)
{
......
}
This is a very attractive solution. The Code uses a catch clause to catch all exceptions. It looks perfect and concise. In fact, many codes are written like this. However, there are two potential defects. One is for each exception thrown in the try block, which may require different processing and recovery measures. Because there is only one catch block, separate processing cannot be achieved. Second, the try block may also throw a runtimeexception. The Code captures all runtimeexceptions that may be thrown without any processing. This masks programming errors and makes the program difficult to debug.
The correct code is as follows:
Try
{
Method1 (); // Method1 throws exceptiona
Method2 (); // Method1 throws predictionb
Method3 (); // Method1 throws exceptionc
}
Catch (effectiona E)
{
......
}
Catch (exceptionb E)
{
......
}
Catch (exceptionc E)
{
......
}
3. 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 in 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.
It must be noted 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.
4. Exceptions cannot affect the object status.
After an exception is generated, the object state cannot be affected. This is an important rule in exception handling. In a function
When an exception occurs, the object state should be consistent with that before calling this function to ensure that the object is in the correct state.
If an object is an immutable object (an immutable object refers to an object that cannot be changed after the constructor is created, that is
There is no way to change the object state after creation), so the object state will certainly not change after an exception occurs. If the object is a mutable object, you must ensure that exceptions do not affect the object state in programming. There are three methods to achieve this goal:
(1) separate code that may generate exceptions from code that changes the object state. Execute Code that may generate exceptions first. If an exception occurs, the code that changes the object state is not executed.
(2) define a recover Method for methods that are not easy to separate and generate abnormal code and change object state code. After an exception is generated, call the recover method to fix the changed class variables, restore the class status before a method call.
(3) Use object copy in the method. In this way, when an exception occurs, only copying is affected and the object itself is not affected.
5. Lost exceptions
See the following code:
Public void method2 ()
{
Try
{
......
Method1 (); // Method1 performs 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. Pray that the Method1 method is shorter.
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:
Public class myexceptionextends exception
{
// Constructor
Public smexception (throwable cause)
{
This. Cause _ = cause;
}
Public myexception (string S, throwable cause)
{
Super (s );
This. Cause _ = cause;
}
// Reload the printstacktrace method to print the original exception stack information
Public void printstacktrace ()
{
If (cause _! = NULL)
{
Cause _. printstacktrace ();
}
Super. printstacktrace (s );
}
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 );
}
// Original exception
Private throwable cause _;
}
6. Do not use both the exception mechanism and return value for exception handling.
Below is a piece of code in our project
Try
{
Dosomething ();
}
Catch (myexception E)
{
If (E. geterrcode =-1)
{
......
}
If (E. geterrcode =-2)
{
......
}
......
}
If you look at this code after a while, can you understand what it means? The mixed use of Java exception handling mechanisms and return values makes the exception handling part of the program "ugly" and hard to understand. If there are multiple different exceptions, different exceptions are defined, instead of using both exception and return values as in the code above.
The correct code after modification is as follows:
Try
{
Dosomething (); // throw myexceptiona and myexceptionb
}
Catch (mydomaintiona E)
{
......
}
Catch (myexceptionb E)
{
......
}
7. Do not make the try block too large
For the purpose of saving trouble, many people are used to using a large try block to contain all the code that may generate exceptions,
There are two disadvantages:
When reading the code, it is difficult to know which code throws exceptions in the lengthy try block code, which is not conducive to code maintenance.
Using try to catch exceptions is at the cost of program execution efficiency. The code that does not need to catch exceptions is included in try blocks, which affects the efficiency of code execution.
References
[1] JOSHUA Bloch valid tive Java programming language guide
[2] http://java.sun.com/