可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
This is more a general purpose programming question than language specific. I've seen several appraoches to try and catches.
One is you do whatever preprocessing on data you need, call a function with the appropriate arguments and wrap it into a try/catch block.
The other is to simply call a function pass the data and rely on try catches within the function, with the function returning a true/false flag if errors occured.
Third is a combination with a try catch outside the function and inside. However if the functions try catch catches something, it throws out another exception for the try catch block outside the function to catch.
Any thoughts on the pros/cons of these methods for error control or if there is an accepted standard? My googling ninja skills have failed me on finding accurate data on this.
回答1:
In general, an exception should only be caught if it can actually be handled.
It makes no sense to catch an exception for no purpose other than to log it. The exception is that exceptions should be caught at the "top level" so that it can be logged. All other code should allow exceptions to propagate to the code that will log them.
回答2:
I think the best way to think about this is in terms of program state. You don't want a failed operation to damage program state. This paper describes the concept of "Exception Safety".
In general, you first need to decide what level of exception safety a function needs to guarantee. The levels are
- Basic Guarnantee
- Strong Guarantee
- NoThrow Guarantee
The basic Guarantee simply means that in the face of an exception or other error, no resources are leaked, the strong guarantee says that the program state is rolled back to before the exception, and nothrow methods never throw exceptions.
I personally use exceptions when an unexpected, runtime failure occurs. Unexpected means to me that such a failure should not occur in the normal course of operations. Runtime means that the error is due to the state of some external component outside of my control, as opposed to due to logic errors on my part. I use ASSERT()'s to catch logic errors, and I use boolean return values for expected errors.
Why? ASSERT isn't compiled into release code, so I don't burden my users with error checking for my own failures. That's what unit tests and ASSERTS are for. Booleans because throwing an exception can give the wrong message. Exceptions can be expensive, too. If I throw exceptions in the normal course of application execution, then I can't use the MS Visual Studio debugger's excellent "Catch on thrown" exception feature, where I can have the debugger break a program at the point that any exception is thrown, rather than the default of only stopping at unhandled (crashing) exceptions.
To see a C++ technique for the basic Guarantee, google "RAII" (Resource Acquisition is Initialiation). It's a technique where you wrap a resource in an object whose constructor allocates the resource and whos destructor frees the resource. Since C++ exceptions unwind the stack, it guarantees that resources are freed in the face of exceptions. You can use this technique to roll back program state in the face of an exception. Just add a "Commit" method to an object, and if an object isn't committed before it is destroyed, run the "Rollback" operation that restores program state in the destructor.
回答3:
Every "module" in an application is responsible for handling its own input parameters. Normally, you should find issues as soon as possible and not hand garbage to another part of the application and rely on them to be correct. There are exceptions though. Sometimes validating an input parameter basically needs reimplementing what the callee is supposed to do (e.g. parsing an integer) in the caller. In this case, it's usually appropriate to try the operation and see if it works or not. Moreover, there are some operations that you can't predict their success without doing them. For example, you can't reliably check if you can write to a file before writing to it: another process might immediately lock the file after your check.
回答4:
There are no real hard and fast rules around exception handling that I have encountered, however I have a number of general rules of thumb that I like to apply.
Even if some exceptions are handled at the lower layer of your system make sure there is a catch all exception handler at the entry point of your system (e.g. When you implement a new Thread (i.e. Runnable), Servlet, MessasgeDrivenBean, server socket etc). This is often the best place to make the final decision as how your system should continue (log and retry, exit with error, roll back transaction)
Never throw an execption within a finally block, you will lose the original exception and mask the real problem with an unimportant error.
Apart from that it depends on the function that you are implementing. Are you in a loop, should the rest of the items be retried or the whole list aborted?
If you rethrow an exception avoid logging as it will just add noise to your logs.
回答5:
I generally consider if as the caller of the method I can use an exception in any way (like, to recover from it by taking a different approach) or if it makes no difference and just went wrong if the exception occurs. So in the former case I'll declare the method to throw the exception while in the latter I'll catch it inside of the method and don't bother the caller with it.
回答6:
The only question on catching exceptions is "are there multiple strategies for getting something done?"
Some functions can meaningfully catch certain exceptions and try alternative strategies in the event of those known exceptions.
All other exceptions will be thrown.
If there are not any alternative strategies, the exception will be simply thrown.
Rarely do you want a function to catch (and silence) exceptions. An exception means that something is wrong. The application -- as a whole -- should be aware of unhandled exceptions. It should at least log them, and perhaps do even more: shut down or perhaps restart.