Six habits of abnormal handling
Do you think you are a Java expert? Are you sure you have a complete grasp of the Java exception handling mechanism? In the following code, can you quickly identify six problems with exception handling?
1 OutputStreamWriter out = ...
2 Java.sql.Connection conn = ...
3 try {//⑸
4 Statement stat = Conn.createstatement ();
5 ResultSet rs = Stat.executequery (
6 "Select UID, name from user");
7 while (Rs.next ())
8 {
9 Out.println ("ID:" + rs.getstring ("UID")//⑹
10 ", Name:" + rs.getstring ("name"));
11}
Conn.close (); ⑶
Out.close ();
14}
catch (Exception ex)//⑵
16 {
Ex.printstacktrace (); ⑴,⑷
18}
As a Java programmer, you should at least be able to identify two problems. However, if you are unable to find all six questions, please continue reading this article.
This article discusses not the general principles of Java exception handling, as these principles are already well known to most people. What we're going to do is analyze all the common bad habits that are known as "counterexample" (anti-pattern) that violate good coding norms, and help readers familiarize themselves with these typical negative examples, so that they can be acutely aware and avoided in practical work.
One example of a reverse: discarding an exception
Code: 15 Lines-18 lines.
This code captures the exception without any processing and can be considered a killer in Java programming. In terms of the frequency and severity of the problem, it may be comparable to a notorious problem in C + + programs. Does not check to see if the buffer is full. If you see this drop (rather than throw) exception, you can be 99% sure the code is problematic (in rare cases, this code has a reason to exist, but it is best to add a complete comment, so as not to cause misunderstanding).
The error with this code is that the anomaly (almost) always means something is wrong, or at least something unusual has happened, and we should not remain silent and indifferent to the distress signal sent by the program. Calling Printstacktrace is not a "handle exception". Yes, calling Printstacktrace is helpful to the debugger, but after the debugging phase of the program, Printstacktrace should no longer assume the primary responsibility in the exception handling module.
Discarding exceptions is a common situation. Open the documentation for JDK's Threaddeath class, and you can see the following note: "Specifically, although Threaddeath is a ' Normal situation ', but the Threaddeath class is a subclass of the error rather than the exception, because many applications catch all the exception and discard it and ignore it. "This passage means that although threaddeath represents a common problem, the JDK defines Threaddeath as a subclass of the error, given that many applications attempt to catch all exceptions and then do not properly handle them. Because the error class represents a serious problem that the general application should not catch. It is obvious that the bad habit of discarding exceptions is so common that it has even affected the design of Java itself.
So, how should we correct it? There are four main options:
1, handling the exception. Take action on the exception, such as correcting the problem, reminding a person, or doing something else, to determine what action should be taken according to the specific situation. Again, the call Printstacktrace is not considered "handled the exception."
2, throw the exception again. The code that handles the exception, after parsing the exception, thinks that it cannot handle it, and throwing the exception back is an option.
3. Convert the exception to another exception. In most cases, this is an exception that converts a low-level exception to an application-level exception whose meaning is more easily understood by the user.
4, do not catch exceptions.
Conclusion: Since the exception has been caught, it should be treated appropriately. Do not catch the exception and then discard it, ignore.
Counter Example bis: Do not specify a specific exception
Code: 15 lines.
Many times people are attracted to a "wonderful" idea: Catch all the exceptions with a catch statement. The most common scenario is the use of catch (Exception ex) statements. In practice, however, this practice is not worth advocating in the vast majority of cases. Why, then?
To understand why, we must review the purpose of the catch statement. The catch statement indicates that we expect an exception to occur, and we want to be able to handle the exception. The function of an exception class is to tell the Java compiler which exception we want to handle. Since most exceptions derive directly or indirectly from Java.lang.Exception, catch (Exception ex) is equivalent to saying that we want to handle almost any exception.
Take a look at the previous code example. What is the exception that we really want to catch? The most obvious one is SqlException, which is a common exception in JDBC operations. Another possible exception is IOException, because it is to manipulate outputstreamwriter. Obviously, it is not appropriate to handle the two distinct exceptions in the same catch block. It's much better to capture SqlException and IOException separately with two catch blocks. This means that catch statements should try to specify the specific exception type, rather than specifying a exception class that covers too wide a range.
On the other hand, there are many other exceptions that may occur, in addition to these two specific exceptions. For example, what if, for some reason, ExecuteQuery returns null? The answer is to let them continue to throw, that is, you do not have to capture or handle. In fact, we cannot and should not catch all the exceptions that may occur, and other parts of the program have the opportunity to catch exceptions. Until it is finally processed by the JVM.
Conclusion Two: Specify the specific exception type as much as possible in the catch statement, and use multiple catch if necessary. Do not attempt to handle any exceptions that may occur.
Anti-Example three: The resource is not released
Code: 3 Lines-14 lines.
The exception changes the normal execution process of the program. This truth, though simple, is often overlooked. If a program uses resources such as files, sockets, JDBC connections, and even encounters an exception, the resource is properly freed. To do this, Java provides a keyword that simplifies such operations finally.
Finally is a good thing: whether or not there is an exception, finally make sure that the code that performs the cleanup task always has an opportunity to execute before the try/catch/finally block ends. Unfortunately, some people are not used to finally.
Of course, writing finally blocks should be more careful, especially to notice the exceptions thrown within finally blocks. This is the last chance to perform a cleanup task, and try not to make any mistakes that are difficult to handle.
Conclusion Three: Ensure that all resources are released correctly. Make full use of finally keywords.
Counter Example: Details of the exception not indicated
Code: 3 Lines-18 lines.
Take a closer look at this code: what happens if there is an exception inside the loop? Can we get enough information to judge the cause of the internal error in the loop? No. We can only know that something is wrong with the class that is currently being processed, but we cannot get any information to determine the cause of the current error.
The Printstacktrace stack trace function shows the execution flow of the program running to the current class, but provides only some of the most basic information, fails to explain the cause of the actual error, and is not easily interpreted.
Therefore, in the case of an exception, it is best to provide some textual information, such as the classes, methods, and other state information currently being executed, including collating and organizing the information provided by Printstacktrace in a more appropriate way to read.
Conclusion Four: In the exception handling module to provide the right amount of error reason information, organizational error information to make it easy to understand and read.
Counter Example: A too large try block
Code: 3 Lines-14 lines.
You can often see people putting a lot of code into a single try block, which is actually not a good habit. The reason this phenomenon is common is that some people don't want to spend time analyzing which lines of code in a large chunk of code will throw an exception, and what the specific type of exception is. Putting a large number of statements into a single large try block is like stuffing all the groceries into a big box while traveling, but it's not easy to find.
Some beginners often put a large amount of code into a single try block and then declare exception in a catch statement instead of separating the paragraphs that might have an exception and catching their exceptions separately. This practice poses difficulties for the reason that the analysis program throws an exception because too many places in a large piece of code can throw exception.
Conclusion Five: Try to reduce the size of the try block.
Anti-Example six: incomplete output data
Code: 7 Lines-11 lines.
Incomplete data is the invisible killer of Java programs. Take a closer look at this code and consider what happens if the middle of the loop throws an exception. The execution of the loop is, of course, interrupted, and second, the catch block executes?? That's all, there's no more action. What about the data that has been exported? The person or device using the data will receive an incomplete (and therefore erroneous) data without any hint that the data is complete. For some systems, the incomplete data may cause more loss than the system stops running.
The ideal solution is to write some information to the output device, declaring the data incomplete, and another possible method is to buffer the data to be output, to prepare all the data and then output it once.
Conclusion VI: Consider the possible exceptions and the impact of these exceptions on the execution process.
rewritten Code
According to the above discussion, the following is a rewrite of the code. Some might say it's a little bit long-winded, but it has a relatively complete exception handling mechanism.
OutputStreamWriter out = ...
Java.sql.Connection conn = ...
try {
Statement stat = conn.createstatement ();
ResultSet rs = stat.executequery (
"Select UID, name from user");
while (Rs.next ())
{
Out.println ("ID:" + rs.getstring ("UID") + ", Name:" + rs.getstring ("name"));
}
}
catch (SQLException Sqlex)
{
Out.println ("Warning: incomplete data");
throw new ApplicationException ("SQL error while reading data", Sqlex);
}
catch (IOException Ioex)
{
throw new ApplicationException ("IO error when writing data", IOEX);
}
Finally
{
IF (conn!= null) {
try {
Conn.close ();
}
catch (SQLException sqlex2)
{
System.err (This.getclass (). GetName () + ". MyMethod-Cannot close database connection:" + sqlex2.tostring ());
}
}
if (out!= null) {
try {
Out.close ();
}
catch (IOException Ioex2)
{
System.err (This.getclass (). GetName () + ". MyMethod-Cannot close output file" + ioex2.tostring ());
}
}
}
The conclusion of this paper is not the universal dogma, sometimes the best teacher is common sense and experience. If you have no confidence in your approach, be sure to add a detailed, comprehensive note.
On the other hand, do not laugh at these mistakes and ask yourself if you are really getting rid of these bad habits. Even the most experienced programmers can go astray occasionally, for the simple reason that they do bring convenience. All of these examples can be seen as the demons of the Java programming world, they are beautiful, pervasive, and always tempting. Perhaps some people will think that these are chicken skin garlic hair Small matter, not mentioning, but please remember: do not to evil small but for it, not to good small but not.