Why should we talk about exception handling in the Java EE project? Perhaps many Java beginners want to say: "Exception handling is not try....catch...finally?" Who's going to do this? ”。 The author in the beginner Java also think so. How do I define an exception class in a multi-tiered Java project? How do I handle exceptions in each layer of the project? When is the exception thrown? When is the exception recorded? How should exceptions be recorded? When needs to convert checked Exception into unchecked Exception, when should unchecked Exception be converted into checked Exception? Should the exception be rendered to the front-end page? How do I design an exception frame? This paper will discuss these problems.
1. Java Exception Handling
In a procedural programming language, we can use the return value to determine whether the method is performing properly. For example, in a program written in C, return 1 if the correct execution of the method. Error returns 0. In VB or Delphi development of the application, when there is an error, we will pop a message box to the user.
We do not get the details of the error through the return value of the method. Perhaps because the method is written by different programmers, the returned results and error messages do not match when the same type of error occurs in different methods.
So the Java language takes a unified exception handling mechanism.
What is an exception? Errors that occur at run time that can be caught and handled.
In the Java language, exception is the parent class for all exceptions. Any exceptions are extended to the exception class. Exception is equivalent to an error type. If you want to define a new error type, extend a new exception subclass. The advantage of using exceptions is that you can pinpoint the location of the source code that caused the program error and get detailed error messages.
Java exception handling is implemented through five keywords, try,catch,throw, throws, finally. The specific exception handling structure is implemented by try....catch....finally blocks. A try block holds a Java statement that may have an exception, which is used to catch the exception that occurred and to handle the exception. Finally blocks are used to purge resources that are not freed in the program. Finally blocks are always executed, regardless of how the code in the try block is returned.
A typical exception handling code
public string GetPassword (String userId) throws dataaccessexception{
String sql = "Select password from userinfo where Userid= ' "+userid +" ";
String password = null;
Connection con = null;
Statement s = null;
ResultSet rs = null;
try{
con = getconnection ();//Get data connection
s = con.createstatement ();
rs = s.executequery (sql);
while (Rs.next ()) {
password = rs.getstring (1);
}
Rs.close ();
S.close ();
}
Catch (SqlException ex) {
throw new DataAccessException (ex);
}
finally{
try{
if (con!= null) {
con.close ();
}
}
Catch (SQLException sqlex) {
throw new DataAccessException ("Shutdown Connection Failed!", Sqlex);
}
return password;
}
You can see the advantages of the Java exception handling mechanism:
A unified classification of errors is implemented by extending the exception class or its subclasses. This avoids the same error and may have different error messages in different methods. When the same error occurs in different methods, you only need to throw the same exception object.
Get a more detailed error message. With exception classes, you can give an exception a more detailed, more useful error message to the user. For the user to track and debug the program.
Separate the correct return result from the error message. Reduces the complexity of the program. There is no need for the caller to know more about the return result.
Force the caller to handle the exception and improve the quality of the program. When a method declares a need to throw an exception, the caller must use the Try....catch block to handle the exception. Of course, the caller can also let the exception continue to throw to the upper layer.
2. Checked exception or unChecked exception?
Java exceptions fall into two broad categories: checked exceptions and unchecked exceptions. All inherited java.lang.Exception exceptions belong to the checked exception. All inherited java.lang.RuntimeException exceptions belong to the unchecked exception.
When a method calls a method that may throw a checked exception, the exception must be captured or thrown back through the Try...catch block.
Let's look at the declaration of the Createstatement () method of the connection interface.
Public Statement createstatement () throws SQLException;
SqlException is a checked exception. When the Createstatement method is invoked, the Java coercion caller must capture the SqlException. Public
string GetPassword (String userId) {
try{
... Statement s = con.createstatement ();
..... Catch (SQLException sqlex) {
...
}
...
}
Or
public string GetPassword (String userId) throws sqlexception{
Statement s = con.createstatement ();
}
(Of course, like connection,satement these resources need to be shut down in time, only to show that the checked exception must force the caller to catch or continue to throw)
Unchecked exceptions are also known as run-time exceptions, which typically represent exceptions that users cannot recover, such as the inability to obtain a database connection, the inability to open files, and so on. Although users can also catch unchecked exceptions just as they do with checked exceptions. However, if the caller does not capture the unchecked exception, the compiler does not force you to do so.
For example, the code for converting a character to an integer value is as follows:
String str = "123";
int value = Integer.parseint (str);
The parseint method signature is:
Public Staticint parseint (String s) throws NumberFormatException
NumberFormatException is thrown when the incoming argument cannot be converted to the appropriate integer. Because NumberFormatException is extended to RuntimeException, it is a unchecked exception. So there is no need to invoke the Parseint method Try...catch
Because Java does not force callers to catch or throw unchecked exceptions. So programmers always like to throw unchecked exceptions. Or when a new exception class is needed, it is always customary to extend from runtimeexception. When you go to call it some methods, if there is no corresponding catch block, the compiler will always let you through, and you do not have to understand what this method will throw out the exception. This may seem like a good idea, but it's far from the real intent of Java exception handling. and misleading to programmers calling your class, because the caller has no idea of the circumstances under which the exception should be handled. The checked exception can explicitly tell the caller what exceptions are needed to invoke this class. If the caller does not process, the compiler prompts and is unable to compile the pass. Of course it is up to the caller to decide what to do with it.
So Java recommends that people should use checked exceptions in their application code. As we mentioned in the previous section, the good thing about using exceptions is that you can force the caller to handle the exception that will be generated. Checked exceptions are used as standard in Java official documents, including the Java Tutorial.
Using checked exceptions should mean that there are a lot of try...catch in your code. After writing and processing more and more try...catch blocks, many people are finally beginning to wonder if the checked anomaly should be used as a standard use.
Even Bruce Eckel, author of the famous "Thinking in Java", has changed his mind. Bruce Eckel even advocated the use of unchecked anomalies as standard. and published articles to test whether checked exceptions should be removed from Java. Bruce Eckel: "When it comes to a small amount of code, the checked exception is undoubtedly a very elegant idea and helps to avoid many potential bugs." But experience shows that the results are just the opposite for a lot of code.
A detailed discussion of checked anomalies and unchecked exceptions can be referred to
"Java Tutorial" http://java.sun.com/docs/books/tutorial/essential/exceptions/runtime.html
Using checked exceptions can cause a lot of problems.
Checked exception causes too much Try...catch code
There may be a lot of checked exceptions that are not reasonably handled by developers, such as SqlException. And developers have to do try...catch. When a developer fails to handle a checked exception correctly, it is usually simple to print out the exception or simply do nothing. Especially for the novice, too much checked abnormal let him feel at a loss.
try{...
Statement s = con.createstatement ();
..... Catch (SQLException sqlex) {
sqlex.printstacktrace ();
}
Or
try{...
Statement s = con.createstatement ();
..... Catch (SQLException sqlex) {
//do Nothing
}
Checked exceptions cause a lot of incomprehensible code generation
When a developer has to catch a checked exception that he or she cannot handle correctly, it is usually encapsulated into a new exception and then thrown. Doing so does not bring any benefits to the program. It makes the code too late to understand.
Just as we use the JDBC code, we need to deal with a lot of try...catch, and really useful code is contained within Try...catch. Makes it difficult to understand this method.
The checked exception causes the exception to be continuously encapsulated into another class exception and then thrown
public void MethodA () throws exceptiona{
..... throw new Exceptiona ();
}
public void MethodB () throws exceptionb{
try{
MethodA ();
...
} catch (Exceptiona ex) {
throw new exceptionb (ex);
}
}
public void Methodc () throws exceptinc{
try{
methodb ();
..
}
catch (Exceptionb ex) {
throw new Exceptionc (ex);
}
}
We see that the anomaly is so layered and endlessly encapsulated and thrown back.
Checked exception leads to broken interface method
A method on an interface has been used by more than one class, and when an extra checked exception is added for this method, all code calling this method needs to be modified.
The above problems can be seen because the caller cannot handle the checked exception properly and is forced to capture and process it, and is forced to encapsulate it and then throw it back. This is very inconvenient and does not bring any benefits. In this case, the unchecked exception is usually used.
chekced exceptions are not without a virgin, and checked exceptions are much more useful than traditional programming error-return values. The compiler ensures that proper handling of exceptions is much better than judging by the return value.
If an exception is fatal, it cannot be recovered. Or the caller has no benefit in capturing it, using the unchecked exception.
If an exception can be recovered, it can be handled correctly by the caller, using the checked exception.
When using a unchecked exception, you must specify in the method declaration the unchekced exception that the method might throw. By the caller himself to determine whether to catch unchecked exception
When to use checked exception, when to use unchecked exception? Does not have an absolute standard. But the author can give some suggestions
When all callers must handle this exception, the caller can retry the operation, or the exception corresponds to the second return value of the method. Use the checked exception.
This exception is only a few of the more advanced callers can handle, the general caller is not properly handled. Use the unchecked exception. Capable callers can perform advanced processing, and the general caller simply does not handle them.
This exception is a very serious error, such as a database connection error, the file cannot be opened, and so on. Or these exceptions are related to the external environment. It is not a retry to resolve. Use the unchecked exception. Because once this exception occurs, the caller simply cannot handle it.
If you are unsure, use the unchecked exception. and describe in detail the exceptions that might be thrown, so that the caller can decide whether to process them or not.
3. To design a new exception class
When designing a new Exception class, first look at whether the exception class is really needed. In general, try not to design new exception classes, but try to use the exception classes that already exist in Java.
Such as
Whether the new exception is a chekced exception or a unchecked exception. We all have to consider the problem of nesting exceptions.
public void MethodA () throws exceptiona{
..... throw new Exceptiona ();
}
Method MethodA declaration throws Exceptiona.
public void MethodB () throws Exceptionb
The MethodB declaration throws exceptionb, and when MethodA is invoked in the MethodB method, Exceptiona cannot handle it, so Exceptiona should continue to throw it up. One way to do this is to throw the MethodB declaration Exceptiona. But this has changed the MethodB method signature. Once changed, all methods that invoke MethodB are changed.
Another option is to encapsulate the Exceptiona into exceptionb and then throw it. If we do not encapsulate Exceptiona in exceptionb, we lose the root exception information, making it impossible to track the original source of the exception.
public void MethodB () throws exceptionb{
try{
MethodA ();
...
} catch (Exceptiona ex) {
throw new exceptionb (ex);
}
}
As in the code above, EXCEPTIONB is nested with a exceptiona. We call Exceptiona "cause anomaly" for the moment, because Exceptiona lead to the production of exceptionb. This will not cause the exception information to be lost.
So when we define a new exception class, we must provide a constructor that can contain nested exceptions. And there is a private member to save this "cause anomaly".
Public Class EXCEPTIONB extends exception{
private throwable cause;
Public exceptionb (String msg, throwable ex) {
super (msg);
This.cause = ex;
}
Public exceptionb (String msg) {
super (msg);
}
Public exceptionb (Throwable ex) {
this.cause = ex;
}
}
Of course, when we call the Printstacktrace method, we need to print out all the "cause exception" information at the same time. So we need to overwrite the Printstacktrace method to display all the exception stack traces. Includes stack traces for nested exceptions.
public void Printstacktrace (Printstrean PS) {
if (cause = null) {
super.printstacktrace (PS);
} else{
ps.println (this);
Cause.printstacktrace (PS);
}
A complete support nesting checked exception class source is as follows. We're here to call it nestedexception.
Public Nestedexception extends exception{
private throwable cause;
Public nestedexception (String msg) {
super (msg);
}
Public nestedexception (String msg, throwable ex) {
super (msg);
This.cause = ex;
}
Public Throwable Getcause () {return
(this.cause ==null? this:this.cause);
Public GetMessage () {
String message = Super.getmessage ();
Throwable cause = Getcause ();
if (cause!= null) {Message
= message + '; nested Exception is ' + cause;
}
return message;
}
public void Printstacktrace (PrintStream PS) {
if (Getcause = null) {
super.printstacktrace (PS);
} else{
ps.println (this);
Getcause (). Printstacktrace (PS);
}
}
public void Printstacktrace (Printwrite pw) {
if (getcause () = = null) {
super.printstacktrace (PW);
}
else{
pw.println (this);
Getcause (). Printstacktrace (PW);
}
}
public void Printstacktrace () {
printstacktrace (system.error);
}
}
Also design a unchecked exception class is the same as above. Just need to inherit runtimeexception.
4. How to record an exception
As a large application system, log files are required to record the operation of the system, so as to track and record the operation of the system. The exceptions to the system are naturally recorded in the log system.
public string GetPassword (String userId) throws nosuchuserexception{
UserInfo user = Userdao.queryuserbyid (userId) ;
If (user = = null) {
logger.info ("The user information is not found, userid=" +userid);
throw new Nosuchuserexception ("The user information is not found, userid=" +userid);
}
else{return
User.getpassword ();
}
public void Senduserpassword (String userId) throws Exception {
UserInfo user = null;
try{
user = GetPassword (userId);
..... SendMail ();
}catch (Nosuchuserexception ex) (
logger.error ("Not found this user information:" +userid+ex);
throw new Exception (ex);
}
We note that one error has been recorded two times. In the wrong place of origin we only record at info level. In the Senduserpassword method, we also record the entire exception information.
I have seen a lot of items are such an abnormal record, regardless of 3721, only encountered an exception to the entire exception recorded. If an exception is thrown repeatedly by a constant encapsulation, it is logged several times. So where should the anomalies be recorded?
The exception should be recorded at the location where it was originally created!
If you must catch an exception that cannot be handled correctly, simply encapsulate it into another exception and throw it up. You do not have to record the exception that has already been recorded again.
If an exception is caught, this exception can be handled. You do not need to log the exception
Public date getDate (String str) {
Date applydate = null;
SimpleDateFormat format = new SimpleDateFormat ("mm/dd/yyyy");
try{
applydate = Format.parse (APPLYDATESTR);
}
catch (ParseException ex) {
//slightly, when malformed, returns null
} return
applydate;
}
When you capture an unspecified exception or external system exception, you should record the details of the exception
try{...
String sql= "SELECT * from UserInfo";
Statement s = con.createstatement ();
..... Catch (SQLException sqlex) {
logger.error ("SQL execution Error" +sql+sqlex);
}
It may be a matter of opinion where the exception information is recorded and how it is logged. Even some systems make exception classes a record exception. When a new exception object is generated, the exception information is automatically logged.
public class Businessexception extends Exception {
private void Logtrace () {
StringBuffer buffer=new StringBuffer ();
Buffer.append ("Business Error in Class:");
Buffer.append (GetClassName ());
Buffer.append (", Method:");
Buffer.append (Getmethodname ());
Buffer.append (", messsage:");
Buffer.append (This.getmessage ());
Logger.error (Buffer.tostring ());
}
Public Businessexception (String s) {
super (s);
Race ();
}
This seems to be very beautiful, in fact, inevitably caused the exception to be repeated records. At the same time, it violates the principle of "responsibility distribution of Class", which is a bad design. Logging exceptions do not belong to the exception class, and logging exceptions should be done by a dedicated logging system. And the record information for the exception is constantly changing. We should give richer information in the recording of anomalies. In order to help us to find the source of the problem based on the exception information to solve the problem.
While we have a lot of discussion about record anomalies, too much emphasis on these things makes developers more puzzled, a good way is to provide the system with an exception handling framework. The framework determines whether to log exceptions and how to log them. Rather than being decided by the ordinary procedure. But it's good to know something.
5. Exception handling in the Java EE project
At present, the Java-EE project is generally divided into multiple layers logically. The classic is divided into three layers: the presentation layer, the business layer, the integration layer (including database access and external system access).
The Java EE project has its complexity, the exception handling of the Java project needs special attention to several problems.
In distributed applications, we encounter many checked exceptions. All RMI calls (including EJB remote interface calls) throw java.rmi.RemoteException, while remoteexception are checked exceptions, when we make remote calls in the business system, We all need to write a lot of code to handle these checked exceptions. And once remoteexception these checked anomalies are very serious to the system, there is hardly any possibility of retrying. In other words, when there are remoteexception these terrible checked anomalies, we have no need to retry, but must write a lot of Try...catch code to deal with it. Generally we are at the bottom of the RMI call, as long as there is an RMI call, all the upper layer of the interface will be required to throw remoteexception exception. Because the way we deal with RemoteException is to continue to throw it up. This will destroy our business interface. RemoteException These Java EE system-level anomalies seriously affect our business interface. The goal of tiering our systems is to reduce dependencies between systems, and the technical changes at each level do not affect the other layers.
Public
class usersoaimplimplements usersoa{public
UserInfo getuserinfo (String userId) throws remoteexception{
//...
Remote method call.
...
}
}
Public interface usermanager{Public
UserInfo getuserinfo (stirng userId) throws RemoteException;
Similarly, JDBC Access throws SqlException checked exceptions.
To avoid the deep intrusion of system-level checked anomalies into the business system, we can define a business system's own exception for the business method. For these very serious anomalies like sqlexception,remoteexception, we can define a new unchecked anomaly and then put SqlException, RemoteException is encapsulated into a unchecked exception and thrown.
If this system-level exception is to be handled by a previous-level caller, you can define a checked business exception and then throw the system-level exception hold as a business-level exception.
Generally, we need to define a unchecked exception so that all the methods of the integration layer interface declare the unchecked exception thrown.
Public dataaccessexceptionextends runtimeexception{...
}
Public interface userdao{Public
string GetPassword (String userId) throws DataAccessException;
public class userdaoimplimplements userdao{public
String GetPassword (String userId) throws dataaccessexception{
String sql = "Select password from userInfo where userid= '" +userid+ "";
try{...
JDBC calls
s.executequery (SQL);
..
} catch (SQLException ex) {
throw new DataAccessException ("Database query Failed" +sql,ex);}}
Defines a checked business exception that enables all methods of the interface of the business layer to declare a checked exception to be thrown.
public class Businessexceptionextends exception{...
}
Public interface usermanager{Public
Userinfo copyuserinfo (Userinfo user) throws businessexception{
NewUser = null;
try{
NewUser = (Userinfo) user.clone ();
} catch (Clonenotsupportedexception ex) {
throw new businessexception ("does not support the Clone method:" +userinfo.class.getname (), ex);
}
}
The Java EE presentation layer should be a very thin layer, the main function is: To obtain the page request, the parameters of the page assembled into a Pojo object, call the corresponding business methods, and then the page forwarding, the corresponding business data presented to the page. The presentation layer needs to pay attention to a problem, the presentation layer needs to verify the legality of the data, such as some input fields can not be empty, character length verification.
Java EE from all the pages to the background parameters are character, if you require input values or date type parameters, you must convert the character value to the corresponding numeric or date value.
If the presentation layer code checksum parameter is not valid, should return to the original page, let the user re-enter the data, and prompts the relevant error message.
Usually converts a parameter from the page to a numeric value, and we can see that the code
Modeandview HandleRequest (httpservletrequest request,httpservletresponse response) throws exception{
String Agestr = Request.getparameter ("Age");
int age = Integer.parse (AGESTR);
....... String birthdaystr = request.getparameter ("Birthday");
SimpleDateFormat format = new SimpleDateFormat ("mm/dd/yyyy");
Date birthday = Format.parse (BIRTHDAYSTR);
}
The code above should be seen frequently, but when the user enters a character from the page that cannot be converted to an integer or an incorrect date value.
The Integer.parse () method is thrown with a numberformatexception unchecked exception. But this anomaly is definitely not a fatal exception, generally when the user in the page input domain input value is not legitimate, we should prompt users to re-enter. But once the unchecked exception is thrown, there is no chance of retrying. Code like this causes a lot of exception information to be displayed to the page. Make our system look very fragile.
Similarly, the Simpledateformat.parse () method throws a ParseException unchecked exception.
In this case we should all catch these unchecked exceptions and give the prompt user a new entry.
Modeandview HandleRequest (httpservletrequest request,httpservletresponse response) throws exception{
String Agestr = Request.getparameter ("Age");
String birthdaystr = request.getparameter ("Birthday");
int age = 0;
Date birthday = null;
try{
Age=integer.parse (AGESTR);
} catch (NumberFormatException ex) {
error.reject ("Age", "not a valid integer value");
}
....... try{
SimpleDateFormat format = new SimpleDateFormat ("mm/dd/yyyy");
Birthday = Format.parse (BIRTHDAYSTR);
} catch (ParseException ex) {
error.reject ("Birthday", "is not a valid date, please enter the ' mm/dd/yyy ' format Date");
}
In the presentation layer it is important to figure out whether the calling method throws a unchecked exception and, in any case, throws the exception and makes the correct handling.
Calling the system's business methods at the presentation layer, there is generally no need to catch exceptions. If the calling business method throws an exception that is equivalent to the second return value, it needs to be caught in this case.
The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.