The risk brought by exception (2)

zhaozj2021-02-16  64

Do not capture generic exceptions in complex software, often there will be a variety of different exceptions when there are some specific code blocks. Dynamically load a class and instantiate an object may generate several different exceptions, including ClassNotFoundException, InstantiationException, IllegaCcessException, and ClassCastException.

A busy programmer may simply call the method in a TRY / CATCH block that can only capture the exception of exception, not add four different Catch blocks to the TRY block (see below) Code Listing 3). This seems to be unable to make some unconscious deposit effect. For example, if classname () is null, Class.Forname () will throw a nullpointRexception exception and captured in this method. In this case, Catch block will capture this exception. Although it never intends to capture such an exception, only because NullPointerexception is a subclass of RuntimeException, and RuntimeException is a subclass of Exception. So a normal catch (Exception E) will capture all RuntimeException subclasses, including NullPointersException, IndexOutOfboundSexception, and ArrayStoreException. Usually, a programmer does not intend to capture these exceptions.

In the code list 3, NULL's classname will cause a nullpointRexception anomaly generation, which tells that the class name is invalid in the call method.

Code list 3

public SomeInterface buildInstance (String className) {SomeInterface impl = null; try {Class clazz = Class.forName (className); impl = (SomeInterface) clazz.newInstance ();} catch (Exception e) {log.error ( "Error creating Class: " ClassName);} Return Impl;

Another result using a generic capture clause is to limit logging because Catch does not know that the special exception is captured. Some of the programmers take the means of adding detection to view the type of abnormality (Code List 4), which is just right with the purpose of using the Catch block.

Code List 4

Catch (eXception E) {if (e instanceof classnotfoundexception) {log.error ("Invalid Class Name: ClassName ", " E.TOString ());} else {log.error (" Cannot Create Class: " ClassName "," E.TOString ());}}

Code List 5 provides an example of a complete capture special exception, and some programmers may have fun to it. Operator InstanceOf is not necessary because this special exception is captured. Each of the checked anomalies (InstantiationException, IllegalaccessException) will be captured and processed. For a class loaded correct, but not implementing a SomeInterface interface, this special case will generate a classcasteexception exception, which will also be verified. Code list 5

public SomeInterface buildInstance (String className) {SomeInterface impl = null; try {Class clazz = Class.forName (className); impl = (SomeInterface) clazz.newInstance ();} catch (ClassNotFoundException e) {log.error ( "Invalid class Name: " ClassName ", " E.TOString ());} catch (instantiationException e) {log.error (" Cannot Create Class: ClassName "," E.TOString ());} catch (ILLEGALACCESSEXCEPTION E) {log.error ("Cannot Create Class: ClassName ", " E.TOSTRING ());} catch (classcastexception e) {log.error (" INVALID CLASS TYPE, " ClassName " Does Not Implement " SomeInterface.class.getname ());} Return Impl;

In some cases, a better way is to re-throw a known exception (or create a new exception) instead of trying to process it in the current method. This allows the calling method to deal with this error in a known context by placing this exception.

The following code Listing 6 provides a replacement version of a buildinterface () method. If a problem occurs when loading and instantiating classes, this version will throw a classNotFoundException exception. In this example, the calling method ensures a correct instantiation or an exception. This calling method does not need to check if the returned object is empty.

Note that this example uses Java 1.4 methods to create a new exception that has been added by additional exception packages to save the original stack tracking information. Otherwise, the stack tracking will indicate that the method BuildInstance () is an exception source, not an exception thrown by NewInstance ().

Code List 6

public SomeInterface buildInstance (String className) throws ClassNotFoundException {try {Class clazz = Class.forName (className); return (SomeInterface) clazz.newInstance ();} catch (ClassNotFoundException e) {log.error ( "Invalid class name:" className "," e.toString ()); throw e;} catch (InstantiationException e) {throw new ClassNotFoundException ( "Can not create class:" className, e);} catch (IllegalAccessException e) {throw new ClassNotFoundException ( "Cannot Create Class:" ClassName, E);} catch (classcastexception e) {throw new classnotfoundexception (ClassName "Does Not Implement" SomeInterface.class.getName (), e);}} In some cases, this The segment code may not be recovered from some kind of error status, at this time, a special exception is captured to make the code can indicate whether some state is recoverable. Please try to see an example of instantiation in the code list 6 in this point of view.

In the code list 7, if the className is invalid, the program returns a default object and throws an exception to indicate the illegal operation, such as the wrong transformation or access.

Note: IllegalClassexception is a series of exception classes, which refers to the purpose of demonstration (translation: is not the Java Standard Library).

Code List 7

public SomeInterface buildInstance (String className) throws IllegalClassException {SomeInterface impl = null; try {Class clazz = Class.forName (className); return (SomeInterface) clazz.newInstance ();} catch (ClassNotFoundException e) {log.warn ( "Invalid class name: " className ", using default ");} catch (InstantiationException e) {log.warn (" Invalid class name: " className ", using default ");} catch (IllegalAccessException e) {throw new IllegalClassException ( "Can not create class:" className, e);} catch (ClassCastException e) {throw new IllegalClassException (className "does not implement" SomeInterface.class.getName (), e);} if (impl == NULL) {impl = new defaultimplemrtation ();} Return Impl;} When should I capture a generic exception?

It is possible to capture a generic exception in some cases, such as when it is convenient and must capture a generic exception. This situation is very special and is important for large, allowable systems. In the code list 8, the request is read from a request queue and sequentially handles. However, when the request is processed, if any exception occurs (a subclass of BadRequestexception or any runtimeException, including nullpointerException), the exception will be captured outside the While loop. This will cause a loop termination and any remaining requests will not be processed. That means dealing with an error during request processing is a poor way. Code list 8

public void processAllRequests () {Request req = null; try {while (true) {req = getNextRequest (); if (req = null!) {processRequest (req); // throws BadRequestException} else {// Request queue is empty Must be done break;}}} catch (badrequestexception e) {log.error ("Invalid Request:" Req, E);}}

A preferred method of operation request processing is two important changes to the logic of the above code, first shift the TRY / CATCH block into the loop of the request processing. In that case any errors are captured and processed inside the loop and will not cause cyclic termination. Thus, the loop will continue to handle the request, even if a single request fails. Second, change this TRY / CATCH block to capture a generic exception. Thus, any exception is captured inside the loop, and the request can be processed. Please see the following code list 9: Code List 9:

public void processAllRequests () {while (true) {Request req = null; try {req = getNextRequest (); if (req = null!) {processRequest (req); // Throws BadRequestException} else {// Request queue is empty Must be done break;}} catch (exception e) {log.error ("Error Processing Request: Req, E);}}

Capturing a generic exception sounds like it is directly contrary to the views beginning with this article, it is true. However, this is just in a very special environment. In this case, a generic exception is captured to prevent a single exception from being terminated throughout the system.

In the case where the request, transaction, or event is processed in a loop, even if there is abnormality during processing, the loop still needs to be executed to continue to process.

In the code list 9, the TRY / CATCH block is considered to be a top-level Exception Handler in the processing cycle, and it needs to capture and record all exceptions caused by this code level. In this way, the abnormality is not neglected, nor will it be lost, and an exception does not interrupt the request for processing.

Each large, complex system has a top exception manager (or every subsystem, depending on how the system is complete). Top abnormal managers are unintentionally to repair potential problems caused by abnormalities and can capture and record this problem without terminating processing. This is not implying that all exceptions should be thrown at this level. Any exception should be done if it can be processed at a lower level. If so, the abnormality processing will know more about the status logic when the problem occurs. However, if an exception cannot be processed at a lower level, throw it to a higher level, so that all unrecoverable errors will be processed (top exception managers), not throughout the system.

Do not throw generic abnormalities The entire issue in Program Listing 1 is to start with the programmer to throw generic anomalies from the Cleanupeverything () method, so that the code becomes very beautiful, and when a method throws 6 different When an exception, it will become messy: the method declaration has become understood that the calling method has to capture the six different exceptions, just like the code list 10.

Code list 10

public void cleanupEverything () throws ExceptionOne, ExceptionTwo, ExceptionThree, ExceptionFour, ExceptionFive, ExceptionSix {cleanupConnections (); cleanupFiles (); removeListeners ();} public void done () {try {doStuff (); cleanupEverything (); doMoreStuff () ;} catch (Exceptionone E1) {// log e1} catch (ExceptionTWO E2) {// log e2} catch (Exceptionthree E3) {// log e3} catch (ExceptionFour E4) {// log e4} catch (ExceptionFive E5 ) {// log e5} Catch (ExceptionSIX E6) {// log e6}} However, even if the code is a bit messy, it is clear. Use special exceptions to avoid two very real questions: Throw a generic Exception to hide the details of potential problems, which will lose the opportunity to handle problems. Further, throwing a generic exception to force any code that calls this method either captures the generic exception (as previously described above, this method has a problem), either re-throwing the generic abnormality expansion.

It is representative that when a method declares that it will throw a generic exception Exception, it may have one of the following two reasons: one reason is that this method calls several additional methods, and that Several methods may throw a number of different exceptions (such as mediation mode or facade mode) and hide the details of the abnormal state. Therefore, no matter what problem is just a simple statement, it will throw Exception without creating and throwing an exception (packaged at a lower level). Another situation is where the method is instantiated and throwing generic exception (ie throw new exception ()), because the programmer believes that the exception should not be used to express this situation.

These two aspects can be resolved as long as they think and designed. What is the details? Is that an abnormality really be thrown? This design may include only declare that this method will throw some exceptions that will occur. Another option is something that creates a layer of abnormal wrapping and declaration. In most cases, the abnormality that is throw (or a series of abnormalities) should be as detailed as possible. This more detailed exception provides more information about the wrong state so that this situation is processed or recorded in detail.

If the generic Exception class is selected, it means that any way to call a declaration that will throw an Exception method, or you must declare that it will also throw an Exception, or package this method to call the TRY / TRY / TRY / Catch block. I use this method to explain this problem in front.

Carefully use generic abnormalities to explore a few aspects of handling generic abnormalities: they will never be thrown, nor should they be ignored. They should be rarely captured (only in very special cases). They don't provide detailed information to allow you to go to handle them, so you should carefully capture exceptions when you don't plan.

转载请注明原文地址:https://www.9cbs.com/read-22559.html

New Post(0)