Three principles for effectively handling Java exceptions

Source: Internet
Author: User
Tags stack trace throwable

Exceptions in Java provide a consistent mechanism for identifying and responding to error situations, and effective exception handling can make programs more robust and easy to debug. An exception is a powerful debugging tool that answers the following three questions:

    • What went wrong?
    • Where's the mistake?
    • Why is it wrong?

In the case of a valid use exception, the exception type answers "What" is thrown, the exception stack trace answers "where" throws, the exception message answers "Why" will throw, if your exception does not answer all the above questions, then you may not be very good to use them. There are three principles that can help you maximize the use of exceptions during debugging, and these three principles are:

    • Concrete and clear
    • Early throw
    • Delayed capture

In order to illustrate these three principles of effective exception handling, this paper discusses the jcheckbook of personal financial Manager class, Jcheckbook is used to record and track bank account activities such as access payment and Bill issuing.
Concrete and clear
Java defines the hierarchy of an exception class that begins with Throwable, expands the error and exception, and exception expands Runtimeexception.1.

Figure 1. Java Exception hierarchy

These four classes are generalized and do not provide much error information, although instantiating these classes is syntactically legal (for example: New Throwable ()), but it is best to use them as virtual base classes, using their more specific subclasses. Java has provided a large number of exception subclasses, and you can define your own exception classes if you want to be more specific.

For example: The Java.io package defines the subclass IOException of the exception class, which is more specific filenotfoundexception, Eofexception and objectstreamexception of these ioexception subclasses. Each describes a specific type of I/O error: The file is missing, the exception file ends, and the wrong serialized object stream. The more specific the exception, the better our program can answer the question of what went wrong.

It is also important to try to be clear when catching exceptions. For example: Jcheckbook can process filenotfoundexception by re-asking the user's file name, and for Eofexception, it can continue to run based on the information read before the exception is thrown. If Objectstreamexception is thrown, the program should prompt the user that the file is corrupted and should use a backup file or other file.

Java makes it easy to catch exceptions explicitly, because we can define multiple catch blocks on the same try block, so that each exception is handled appropriately.

File Prefsfile =NewFile (prefsfilename);Try{readpreferences (prefsfile);}Catch(FileNotFoundException e) {//alert the user that the specified file//does not exist}Catch(eofexception e) {//Alert the user that the end of the file//Was reached}Catch(objectstreamexception e) {//Alert the user that's the file is corrupted}Catch(IOException e) {//alert the user that some other I/O//error occurred}

Jcheckbook provides the user with explicit information to catch an exception by using multiple catch blocks. For example, if FileNotFoundException is captured, it can prompt the user to specify another file, and in some cases the extra coding effort from multiple catch blocks may be an unnecessary burden, but in this case, The extra code does help the program provide a more user-friendly response.

In addition to the exceptions handled by the first three catch blocks, the last catch block provides a more generalized error message to the user when the IOException is thrown. In this way, the program can provide specific information as much as possible, but it also has the ability to handle unexpected exceptions.

Sometimes the developer catches the fan exception and displays the exception class name or prints the stack information for "concrete". Don't do this! Users who see java.io.EOFException or stack information only have headaches rather than getting help. You should catch specific exceptions and use "people" to prompt the user for the exact information. However, the exception stack can be printed in your log file. Remember that exceptions and stack information are used to help developers, not users.

Finally, it should be noted that Jcheckbook does not catch an exception in Readpreferences (), but instead leaves the capture and handling exception to the user interface layer, which allows the user to be notified by dialog boxes or other means. This is called "delayed capture" and is discussed below.

Early throw
The exception stack information provides an exact sequence of method call chains that cause exceptions, including the class name, method name, code file name, and even number of rows for each method call to pinpoint the scene where the exception occurred.

Java.lang.NullPointerExceptionat Java.io.FileInputStream.open (Native Method) at Java.io.FileInputStream. <init> (fileinputstream.java:103) at Jcheckbook. Jcheckbook.readpreferences (Jcheckbook.java:225) at Jcheckbook. Jcheckbook.startup (Jcheckbook.java: $) at Jcheckbook. Jcheckbook. <init> (jcheckbook.java:27) at Jcheckbook. Jcheckbook.main (Jcheckbook.java:318)

The above shows the case where the open () method of the FileInputStream class throws NullPointerException. Note that Fileinputstream.close () is part of the standard Java class Library, and it is likely that the problem with this exception is that our code itself is not the Java API. So the question is likely to appear in one of the previous methods, fortunately it is also printed in the stack information.

Unfortunately, NullPointerException is the least amount of information in Java (but also the most often encountered and crashes) exception. It doesn't even mention what we care about the most: where is null. So we had to go back a few steps to find out what went wrong.

By stepping back the trace stack information and examining the code, we can determine that the error was due to an empty file name parameter passed to Readpreferences (). Now that readpreferences () knows it can't handle the empty file name, check the condition immediately:

 Public voidreadpreferences (String filename)throwsillegalargumentexception{if(FileName = =NULL){         Throw NewIllegalArgumentException ("FileName is null"); }  //if//... perform other operations ...InputStream in=Newfileinputstream (filename); //... read the preferences file ...}

By throwing an exception early (also known as "rapid Failure"), the anomaly is clear and accurate. The stack information immediately reflects what went wrong (providing an illegal parameter value), why the error occurred (the file name cannot be a null value), and what was wrong (the first part of Readpreferences ()). This allows our stack information to be provided truthfully:

NULL At Jcheckbook. Jcheckbook.readpreferences (Jcheckbook.java:207) at Jcheckbook. Jcheckbook.startup (Jcheckbook.java: $) at Jcheckbook. Jcheckbook. <init> (jcheckbook.java:27) at Jcheckbook. Jcheckbook.main (Jcheckbook.java:318)

Additionally, the exception information that is contained in it ("file name is empty") is enriched by the question of explicitly answering what is empty, and this answer is not available from the nullpointerexception that we have thrown in our previous code.

Rapid failure by throwing an exception immediately when an error is detected can effectively avoid unnecessary object construction or resource consumption, such as a file or network connection. Also, the cleanup operations that open up these resources can be avoided.

Delayed capture
One of the mistakes that a novice and a master can make is to capture a program before it has the ability to handle the exception. The Java compiler indirectly encourages this behavior by requiring that the detected exception be caught or thrown. It's a natural practice to wrap the code in a try block immediately, and catch the exception using catches to prevent the compiler from getting an error.

The question is, what happens when you catch an exception after the capture? The last thing to do is to do nothing. An empty catch block is tantamount to throwing an entire exception into a black hole, and all the information that explains when and why the error occurred is lost forever. Writing the exception to the log is a little bit better, at least there are records to check. But we can't always expect users to read or understand log files and exception information. It is also inappropriate to have readpreferences () display the Error message dialog box, because although Jcheckbook is currently a desktop application, we plan to turn it into an HTML-based Web application. In that case, displaying an error dialog box is obviously not a choice. At the same time, regardless of the HTML or C/S version, the configuration information is read on the server, and the error message needs to be displayed to the Web browser or client program. Readpreferences () should also take these future requirements into account at design time. Proper separation of user interface code and program logic can improve the reusability of our code.

Catching it prematurely before conditional handling of the exception usually results in more serious errors and other exceptions. For example, if the Readpreferences () method above captures and records the filenotfoundexception that might be thrown as soon as the FileInputStream construction method is called, the code becomes the following:

 public  void   readpreferences (String filename) { // " Span style= "COLOR: #008000" > ...   InputStream in  = null  ;  //  do not do this!!!  try  {in  = new   FileInputStream (filename);}  catch   (FileNotFoundException e) {logger.log (e);} in.read (...);  //  ... } 

The above code captures it when it is completely incapable of recovering from filenotfoundexception. If the file cannot be found, the following method obviously cannot read it. What happens if Readpreferences () is asked to read files that do not exist? Of course, FileNotFoundException will be recorded, if we were to read the log file, we will know. But what happens when the program tries to read data from a file? Since the file does not exist, the variable in is empty, and a nullpointerexception is thrown.

When debugging a program, instinct tells us to look at the information at the back of the log. It's going to be nullpointerexception, and it's really annoying that this anomaly is very not specific. Error messages not only mislead us about what went wrong (the real error is filenotfoundexception rather than nullpointerexception), but it also misleads the wrong source. The real problem lies in the number of rows thrown nullpointerexception, where there may be several methods of invocation and destruction of classes. Our attention was drawn from the real error by this little fish, until we looked back at the log to find the source of the problem.

Since what readpreferences () really should do is not catch these anomalies, what should it be? It seems counterintuitive, and usually the best thing to do is to do nothing and not catch the anomaly right away. Give responsibility to the caller of readpreferences () and let it investigate the appropriate method of handling the missing profile, which may prompt the user to specify a different file, or use the default value, and perhaps warn the user and exit the program.

The way to pass the responsibility of exception handling toward the upstream of the call chain is to declare the exception in the throws clause of the method. When declaring an exception that may be thrown, the more specific the attention, the better. This is used to identify the type of exception that the program calling your method needs to know and is ready to handle. For example, the "delayed capture" version of Readpreferences () might be something like this:

 Public voidreadpreferences (String filename)throwsillegalargumentexception,filenotfoundexception, ioexception{if(FileName = =NULL){           Throw NewIllegalArgumentException ("FileName is null"); }  //if//...InputStream in=Newfileinputstream (filename);//...}

Technically, the only exception we need to declare is IOException, but we explicitly state that the method might throw filenotfoundexception. IllegalArgumentException is not mandatory because it is a non-inspection exception (that is, RuntimeException subclass). However, declaring it is to document our code (these exceptions should also be noted in the Javadocs of the method).

Of course, your program eventually needs to catch an exception, or it will terminate unexpectedly. But the trick here is to catch the exception at the right level so that your program can either recover meaningfully from the exception and continue without causing a deeper error, or provide the user with clear information, including directing them to recover from the error. If your method is not competent, then do not handle the exception, leave it behind to capture and deal with it at the right level.
Conclusion
Experienced developers know that the biggest difficulty in debugging is not fixing bugs, but finding a place to hide from the vast code. By following the three principles of this article, you will be able to help you track and eliminate defects, make your programs more robust, and more user-friendly.

English Original: Jim Cushing, compilation: Importnew-Zheng

Transferred from: http://www.importnew.com/1701.html

Three principles for effectively handling Java exceptions

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.