Throwing a new exception while throwing an old exception
If a destructor throws in C++ during stack unwinding caused by an exception, the program terminates. (That's why destructors should never throw in C++.) Example:
struct Foo
{
~Foo()
{
throw 2; // whoops, already throwing 1 at this point, let's terminate!
}
};
int main()
{
Foo foo;
throw 1;
}
terminate called after throwing an instance of 'int'
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
If a finally block is entered in Java because of an exception in the corresponding try block and that finally block throws a second exception, the first exception is silently swallowed. Example:
public static void foo() throws Exception
{
try
{
throw new Exc开发者_运维问答eption("first");
}
finally
{
throw new Exception("second");
}
}
public static void main(String[] args)
{
try
{
foo();
}
catch (Exception e)
{
System.out.println(e.getMessage()); // prints "second"
}
}
This question crossed my mind: Could a programming language handle multiple exceptions being thrown at the same time? Would that be useful? Have you ever missed that ability? Is there a language that already supports this? Is there any experience with such an approach?
Any thoughts?
Think in terms of flow control. Exceptions are fundamentally just fancy setjmp
/longjmp
or setcc
/callcc
anyway. The exception object is used to select a particular place to jump to, like an address. The exception handler simply recurses on the current exception, longjmp
ing until it is handled.
Handling two exceptions at a time is simply a matter of bundling them together into one, such that the result produces coherent flow control. I can think of two alternatives:
- Combine them into an uncatchable exception. It would amount to unwinding the entire stack and ignoring all handlers. This creates the risk of an exception cascade causing totally random behavior.
- Somehow construct their Cartesian product. Yeah, right.
The C++ methodology serves the interest of predictability well.
You can chain exceptions. http://java.sun.com/docs/books/tutorial/essential/exceptions/chained.html
try {
} catch (IOException e) {
throw new SampleException("Other IOException", e);
}
You can also have a try catch inside your finnally too.
try{
}catch(Exception e){
}finally{
try{
throw new SampleException("foo");
}catch(Exception e){
}
}
Edit:
Also you can have multiple catches. I don't think multiple exceptions would be a good idea, because an exception is already something you need to recover from. The only reason to have more than one exception I can think of is if you use it as part of your logic (like multiple returns), wich would be deviating from the original purpose of the idea of the Exception. Besides, how can you produce two exceptions at the same time?
Could a programming language handle multiple exceptions? Sure, I don't see why not. Would this be useful? No, I would say it would not be. Error handling and resumption is very hard as it is - I don't see how adding combinatorial explosion to the problem would help things.
Yes, it is possible for a language to support throwing multiple exceptions at a time; however, that also means that programmers need to handle multiple exceptions at a time as well, so there is definitely a tradeoff. I have heard of languages that have this although I am having trouble coming up with the list off the top of my head; I believe LINQ or PLINQ may be one of those languages, but I don't quite remember. Anyway, there are different ways that multiple exceptions can be thrown... one way is to use exception chaining, either by forcing one exception to become the "cause" or "previouslyProgatingException" of the other, or to bottle all of the exceptions up into a single exception representing the fact that multiple exceptions have been thrown. I suppose a language could also introduce a catch clause that lets you specify multiple exception types at once, although that would be a poor design choice, IMHO, as the number of handlers is large enough as is, and that would result in an explosion of catch clauses just to handle every single possible combination.
C++ std::exception_ptr allows you store exceptions. So it should be possible to embed exceptions in other exceptions and give you the impression that you have the stack on thrown exceptions. This could be useful if you want to know the root cause of the actual exception.
One situation where multiple thrown exceptions in parallel might be useful, is unit testing with JUnit:
- If a test fails, an exception is thrown (either produced by code under test or an assertion).
- Each
@After
method is invoked after the test, whether the test fails or succeeds. - If an After method fails, another exception is thrown.
- Only the exception thrown in the After method is displayed in my IDE (Eclipse) for the test result.
I know that JUnit notifies its test listeners about both exceptions, and when debugging a test in Eclipse I can see the first exception appearing in the JUnit view, only to be replaced by the second exception shortly after.
This problem should probably be resolved by making Eclipse remember all notifications for a given test, not only the last one. Having "parallel exceptions", where the exception from the finally
does not swallow the one from the try
, would solve this issue too.
If you think about it, the situation you've described has Exception("First")
as the root cause of Exception("second")
, conceptually. The most useful thing for the user would probably be to get a stack dump showing a chain in that order...
In managed platforms, I can think of situations where it might be useful to have a disposer "elevate" an exception to something which is stronger, but not totally fatal to an application. For example, a "command" object's disposer might attempt to unwind the state of its associated connection to cancel any partially-performed commands. If that works, the underlying code may attempt to do other things with the connection. If the attempted "cancel" doesn't work, the exception should probably propagate out to the level where the connection would have been destroyed. In such a case, it may be useful for the exception to contain an "inner exception", though the only way I know to achieve that would be to have the attempted unwinding in a catch block rather than a "finally" block.
精彩评论