It dawned on me that I've never seen a single exception hierarchy for which creating subclasses but catching the parent class was actually useful (except, of course, for the base Exception class, that has to be derived).
Are exception hierarchies really useful, xor should all exceptions be derived from language's base exception class?
Java exception handling is important because it helps maintain the normal, desired flow of the program even when unexpected events occur. If Java exceptions are not handled, programs may crash or requests may fail. This can be very frustrating for customers and if it happens repeatedly, you could lose those customers.
Exceptions provide the means to separate the details of what to do when something out of the ordinary happens from the main logic of a program. In traditional programming, error detection, reporting, and handling often lead to confusing spaghetti code.
The class at the top of the exception class hierarchy is the Throwable class, which is a direct subclass of the Object class. Throwable has two direct subclasses - Exception and Error. The Exception class is used for exception conditions that the application may need to handle.
Exceptions are not bad per se, but if you know they are going to happen a lot, they can be expensive in terms of performance. The rule of thumb is that exceptions should flag exceptional conditions, and that you should not use them for control of program flow.
Exception hierarchies are useful for grouping related exceptions together, when you need different granularity of catching in different places.
Putting all application exceptions in one place is the commonest use case. This allows you to catch MyAppException
any time that you want to trap all errors coming from your application, but still catch more specific exceptions when appropriate. (In .NET, the ApplicationException
class was meant for this, but it's been deprecated for various reasons.)
But you can also group exceptions together at module boundaries, or in any other way that makes sense. Use FooModuleException
for exceptions coming from the Foo
module, but catch and handle FooModuleMustFrobnicate
specially internal to Foo
. Or any equivalent situation.
I've used all of these patterns at different times.
TL;DR
Error
) and "normal" runtime exceptions. The notion that "you need different granularity of catching in different places" is IMHO fundamentally flawed. (Except, to reiterate, to differentiate between exceptions and assertions and other system wide unrecoverable stuff.)I am slowly coming to consider the whole concept of arbitrarily typed exceptions, as I see them implemented and supposed-to-be-used in C++, C# and Java as totally useless.
The problem is not so much the exception hierarchy per se, but that when I write code, and exception are exceptional, I don't care what type of exception was thrown for the purpose of catching it.
In all my coding in C++, Java and C#, I found -- for the exceptional exceptions, that were not misused for control flow -- not one case where I wanted to filter (i.e. catch or not catch) the exceptions by their "hierarchical" type. That is, there are rare cases where a function throws 3 different exceptions, and I want to specifically handle one of them, and handle the two others as general "fail" (like described below) but I never ever encountered this in a case where the exception hierarchy was useful in that I could meaningfully group the two cases by base classes.
If any operation (where I care) in my program fails with any exception, then this operations is considered failed, and:
I think Java is the only of the three languages that at least has the right approach with their hierarchy, namely:
Throwable
not used in user codeError
the stuff you never want to catch - just core dumpException
- for all the stuff you basically always want to catch (except for when an Interface is botched and uses an Exception when it really shouldn't)//
The hierarchy of C++'s <stdexcept>
has the right basic approach in differentiating between logic_error
- basically assertions - and runtime_error
- stuff that just unexpectedly failed. (The subclasses of theses are largely irrelevant when catching.)
Except of course that too much stuff derives directly from std::exception
so you can't make use of the differentiation provided by runtime and logic error. (And of course any code is free to throw whatever they want, so chances are good that there's a bunch of logic_error derived classes that really should be runtime_errors and vice-versa.
To quote another answer:
Exception hierarchies are useful for grouping related exceptions together, when you need different granularity of catching in different places.
but in my experience I never want "catching in different places", because it just doesn't make sense.
I either want catching, in which case I catch everything (modulo stuff like the Error
class exceptions from Java) or I don't want to catch, in which case the hierarchy is not needed, because there is no catch.
Take opening and reading from a file:
If there is (would be) any exception type I specifically care about, because I can do something about it ("recover"), then this should not be reported as an exception at all, because it is normal control flow. (If the error is such-and-such, I can do such-and-such basically locally.)
If on the other hand, I can't do anything about an error but record the file operation as failed, then having any catch granularity is utterly useless.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With