Checked in Java exception--the Demons lurking in the beautiful world?

Source: Internet
Author: User
Tags getmessage

When writing an application in Java, we often need to use a third-party class library to help us do the functions we need. Sometimes many of the APIs provided by these class libraries declare the exceptions they might throw through throws. But when we look at the documentation for these APIs, we have no way of finding a detailed explanation of these exceptions. In this case, we cannot simply ignore the exceptions declared by throws:

1  Public void shouldnotthrowcheckedexception () {2     // The API call may throw an unknown cause of checked Exception 3     Exceptionalapi (); 4 }

Otherwise the Java compiler will make an error because the Shouldnotthrowcheckedexception () function does not declare the checked exception it might throw. However, if the checked Exception that the function may throw is indicated by throws, the other calls to the Shouldnotthrowcheckedexception () function also need to be throws to indicate that it may throw the checked Exception.

Oh, this is a really annoying thing. So how do we deal with these checked exception? In this article, we will briefly describe how to use and process checked exception in Java applications.

Java Introduction to Exceptions

Before we go into detail about the problems caused by checked exception, let's briefly introduce the exceptions in Java in a short space of time.

In Java, exceptions are divided into three main types: Exception,runtimeexception and error. These three types of exceptions are throwable subclasses. The individual exception types that derive directly from Exception are the checked Exception we just mentioned. One of the more special parts of it is forcing callers to handle the exception. Take the example of our common FileReader class for reading a file's contents. It is declared in the constructor declaration of the class that it may throw FileNotFoundException:

1  Public throws FileNotFoundException {2    ... 3 }

So in the function that calls the constructor, we need to pass try...catch ... To handle the exception:

 1  public  void   Processfile () { try   { 3  filereader filereader = Span style= "color: #0000ff;" >new   FileReader (inFile);  4 } catch   (FileNotFoundException exception) { 5  //  6  }  7   ...  8 } 

If we don't pass the try...catch ... To handle the exception, we have to declare the function by throws in the function declaration to throw FileNotFoundException:

1  Public void throws FileNotFoundException {2     New // may throw FileNotFoundException 3     ... 4 }

Each derived class of the RuntimeException class does not have the need to force callers to handle the exception. Why is there such a big difference between these two kinds of anomalies? Because runtimeexception represents a problem that is caused by software developers not writing code correctly, such as array access is out of bounds. Each exception derived from the exception class represents not an unhealthy state caused by the inadequacy of the code itself, but rather a case in which a series of applications cannot control themselves. For example, when an application tries to open a file and writes it, the file is opened by another application and cannot be written. In these cases, Java uses checked exception to force software developers to consider handling these unavoidable situations when writing code, thereby improving the quality of the code.

and error is a series of problems that are difficult to solve through the program. These problems are basically unrecoverable, such as insufficient memory space, and so on. In this case, we basically can't get the program back to normal orbit. Therefore, in general, we do not process individual exceptions that derive from the error class. And because it's actually irrelevant to this article, we're no longer explaining it in detail.

Angels become Demons

Since checked exception in Java can improve the quality of user code, why do so many people oppose it? The reason is simple: it's too easy to be misused. In this section, we will list these misuse scenarios and propose the most recommended solutions on the network.

The ubiquitous throws

The first case of misuse is the widespread spread of checked exception. As mentioned earlier, when invoking an API that might throw checked exception, software developers can have two options. One option is to add the throws declaration on the function that invokes the API and pass the checked exception up:

1  Public void throws FileNotFoundException {2     New // may throw FileNotFoundException 3     ... 4 }

In the code that calls the Processfile () function, the software developer may feel that this is not the right place to handle the exception filenotfoundexception, so he passes the exception up again through throws. But adding throws on a function means that other code that calls the function also needs to handle the throws declaration. In a system with better code reusability, these throws can spread very quickly:

It can be seen from this: if you don't deal with checked Exception, but throw it through throws, more and more functions will be affected. In this case, we have to deal with the checked exception in multiple places.

If you encounter a function overload or an interface implementation in the process of spreading, things will become more cumbersome. This is because throws in a function declaration is actually part of the function signature. If a throws is added to a function overload or an interface implementation, the overloaded function or the corresponding function in the implemented interface also needs to add a throws declaration in order to maintain the original relationship. This change causes other function overloads and the interface implementation to be changed as well:

In, we show the serious consequences of adding throws in an interface declaration. In the beginning, we implemented the interface function Interface::method () in the application. There are six implementations of this in the application and in third-party applications. However, if a checked Exception is thrown in the implementation of the A::method (), it will require that the corresponding function in the interface also add the throws declaration. Once the throws declaration is added to the interface, all implementations of that interface in the application and in the third-party application will need to add the throws declaration, even if there is no function call in those implementations that might throw the exception.

So how do we solve this problem? First, we should deal with checked exception as soon as possible. This is because as checked exception along the trajectory of the function call, the meaning of these thrown checked exception will gradually blur. For example, in the Startupapplication () function, we may need to read the user's profile to configure the app based on the user's original preferences. Because the logic needs to read the user's profile, its internal logic may throw filenotfoundexception at run time. If the filenotfoundexception is not processed in a timely manner, then the signature of the Startupapplication () function will look like this:

1  Public void throws FileNotFoundException {2    ... 3 }

Can a FileNotFoundException exception be generated when an application is launched? Yes, it's easy to understand, but what happened to the anomaly? When reading a preference file or loading a DLL? What kind of processing does the app or user need for this exception? All we can do at this point is to determine where there is an exception by analyzing the information recorded in the exception instance.

Conversely, if we deal with the exception as soon as the checked exception is generated, we will have the most abundant information about the exception at this point:

1  Public voidreadpreference () {2 ...3     Try {4FileReader FileReader =NewFileReader (preferencefile);5}Catch(FileNotFoundException exception) {6         //add a record to the log and use the default settings7     }8 ...9}

But it seems to users that the preferences he once set are no longer valid at this time of use. This is what happens when our program runs, so we need to notify the user that the original preference file no longer exists, so we will use the default app settings. And all of this is done through a derived class of the RuntimeException class defined in our application:

1  Public voidreadpreference () {2 ...3     Try {4FileReader FileReader =NewFileReader (preferencefile);5}Catch(FileNotFoundException exception) {6Logger.log ("Could not find User preference setting file: {0} "preferencefile);7         Throwapplicationspecificexception (Preference_not_found, exception);8     }9 ...Ten}

As you can see, enough information is already contained in the applicationspecificexception exception thrown in the catch block. In this way, our application can capture applicationspecificexception to handle them uniformly and display the most detailed information to the user, notifying him that the default setting is used because the preference file cannot be found:

1 Try {2    startapplication (); 3 Catch (Applicationspecificexception exception) {4    showwarningmessage (Exception.getmessage ( )); 5 }

The Unprepared API user

Another problem related to checked exception is the random handling of it. As you may know in the previous tutorial, if a checked exception cannot be processed in a function called by the API, then the function needs to add a throws declaration, resulting in multiple code needs to be modified for that checked exception. Well, in order to avoid this situation, we will deal with it as soon as possible. But when we looked at the API documentation, we found that there was no detailed explanation for the checked exception in the document:

1 /** 2 * ..... 3 * Throws Somecheckedexception 4  */ 5  Public void throws somecheckedexception {6 }

And there's no way we can see from the signature of the function why the function throws the exception, and we don't know if the exception needs to be visible to the user. In this case, we only intercept it and add a record to the log:

1 Try {2    someFunction (); 3 Catch (Somecheckedexception exception) {4     // add a record to the log 5 }

Obviously, this is not a good practice. and the root cause of all this is not to say exactly why the function throws the checked Exception. So for an API writer, since throws is also part of a function declaration, it is really important to add a clear and accurate document to the checked exception that a function can throw.

Tired of dealing with API users

In addition to the lack of clear documentation, another thing that makes API users very resistant is the overuse of checked exception.

Perhaps you have been exposed to a similar situation: an API for obtaining data in a class library, such as GetData (int index), throws an exception through throws to indicate that the API user passed the parameter index is an illegal value. As you can imagine, because GetData () is likely to be used very frequently, software developers need to use try ... catch for every call ... Block to intercept the exception, which makes the code look messy.

If a class library has one such API, the improper use of this kind of checked exception in this class library is often more than one. Then the API of this class library will pollute the user code massively, make these user code is filled with the try...catch of unnecessary and meaningless ... block, which in turn makes the logic of the code seem extremely obscure.

1Record record =NULL;2 Try {3Record = Library.getdataat (2);4}Catch(Invalidindexexception exception) {5......//Exception Handling Logic6 }7Record.setintvalue (Record.getintvalue () * 2);8 Try {9Library.setdataat (2, record);Ten}Catch(Invalidindexexception exception) { One......//Exception Handling Logic A}

Conversely, if these are not checked Exception, and the software developer can guarantee that the incoming index is legitimate, then the code will be much simpler:

1 Record record = Library.getdataat (2); 2 Record.setintvalue (Record.getintvalue () * 2); 3 Library.setdataat (2, record);

So when should we use checked exception? As mentioned earlier, if an exception represents an unhealthy state that is not the result of a lack of code itself, but a situation in which a series of applications cannot control itself, then we will need to use checked Exception. Take the example of the constructor for the FileReader class listed earlier:

1  Public throws FileNotFoundException

The meaning of the signature of the constructor is actually:

    1. The file that needs to be opened must be marked with the passed-in parameter filename
    2. If the file exists, the constructor returns an instance of the FileReader class
    3. The code used for this constructor must handle the case that the file indicated by filename does not exist and then throws FileNotFoundException

In other words, Checked exception is actually part of the API design. When calling this API, you have to deal with the situation where the target file does not exist. This is caused by the file system's own characteristics. And the reason why checked exception caused so much controversy and misuse, more because we are using the exception this is used to denote the application of the running error of the language composition to inform the user he must deal with the possible situation of the application cannot control. In other words, it gives a new meaning to the exception, making it necessary to represent two completely irrelevant concepts. In the absence of careful discrimination, these two concepts are highly confusing. So before trying to define a checked exception, the API writer first has to consider whether the exception represents a run-through error caused by the system's own flaw, or the edge condition that the user should handle.

use correctly Checked Exception

In fact, how to correctly use checked exception has been explained in detail in the previous chapters. Here we do a summary again, but also to deepen the impression.

From the API Writer's point of view, all he needs to consider is when to use a checked Exception.

First, Checked exception should be used only when exceptions are unavoidable for APIs and users of the API. For example, when a file is opened, neither the API nor the user of the API can guarantee that the file will exist. Conversely, when accessing data through an index, if the user of the API has passed 1 to the parameter index, then this is a code error and is completely avoidable. Therefore, for cases where the index parameter value is incorrect, we should use unchecked Exception.

Second, Checked exception should not be thrown by widely invoked APIs. This is based on code cleanliness considerations, on the other hand, because the checked exception itself is the actual meaning of the API and the user of the API can not be avoided. If an application has too many of these "unavoidable exceptions", then whether the program has enough quality is also a matter of great concern. As far as the API provider is concerned, it is a negation of its own API to throw this exception on a major, widely used feature.

Again, a checked exception should have a definite meaning. The clear meaning of the standard is that the API user will be able to see the checked exception the corresponding exception class, the exception class contains the various domains, and read the corresponding API document will be able to understand exactly where the problem, and to provide users with accurate explanation of the exception.

For the API user, once encountering an API will throw checked Exception, then he needs to consider using a wrapped Exception to wrap the checked Exception. So what is wrapped exception?

To put it simply, wrapped exception is an exception that wraps an exception. In the Try...catch ... When a block is caught to an exception, the message that is logged inside the exception may not be appropriate. Let's take an example of the loading preferences we've already raised earlier. At startup, the app tries to read the user's preferences. These preferences are recorded in a file and may have been mistakenly deleted. In this case, reading the preference file causes a FileNotFoundException to be thrown. But the information logged in the exception is of no value to the user or even to the application writer: "Could not find file Preference.xml while opening file". In this case, we need to construct a new exception, where the exact error message is marked and the FileNotFoundException as the cause of the new exception:

1  Public voidreadpreference () {2 ...3     Try {4FileReader FileReader =NewFileReader (preferencefile);5}Catch(FileNotFoundException exception) {6Logger.log ("Could not find User preference setting file: {0} "preferencefile);7         Throwapplicationspecificexception (Preference_not_found, exception);8     }9 ...Ten}

An exception of type applicationspecificexception has been re-thrown in the example code above. As you can see from its name, it should be an application-specific exception that the API consumer adds to the application implementation. To avoid the need to add a throws declaration for each function in the call stack, the exception needs to be derived from runtimeexception. This allows the application to catch these exceptions at the bottom of the call stack and handle them by adding an exception record to the system log, displaying only the messages in the exception to the user, to prevent the call stack information inside the exception from exposing too many implementation details, and so on:

1 Try {2     ... 3 Catch (Applicationspecificexception exception) {4    logger.log (Exception.getlevel (), Exception.getmessage (), exception); 5     // displays information from the exception internal record to the user (or to the response added to the request) 6     // such as Showwarningmessage (Exception.getmessage ()); 7 }

Reprint please specify the original address and marked reprint: http://www.cnblogs.com/loveis715/p/4596551.html

Commercial reprint please contact me in advance:[email protected]

Checked in Java exception--the Demons lurking in the beautiful world?

Related Article

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.