[See ObserversShouldNeverThrowExceptions for some of the background that led to this page.]
In Java, routines must declare the exceptions that they throw unless they are subclasses of RuntimeException or Error. RuntimeExceptions are intended to be thrown only by program logic errors, such as an array subscript being out of range. Error exceptions are intended to be thrown only by meta object problems, like a problem in the JVM. Both kinds of problem can happen in almost any code so it would be a pain if they did have to be declared. Using the "silent" exceptions for other kinds of error defeats one of the benefits of exception handling: that the error conditions be well-documented and unignorable.
So the first part of this rule says, Use exceptions as they are meant to be used. Don't throw the silent exceptions. Throwing Exception itself is better than doing that.
The second part of this rule is more controversial. It says: Don't throw Exception itself. The reason for this is that the type of the exception conveys information to the caller about what went wrong. The caller may be able to recover from some errors but not from others.
One theory is that you should throw the most specific exception that still makes sense to the caller. If you need to declare a new subclass to describe the problem, so be it. It may worth creating a whole new domain-specific hierarchy of exceptions, rooted in Exception, to provide information at the appropriate level of abstraction.
Another theory says YouArentGonnaNeedIt. Don't use two kinds of Exception where one will do - make sure at least one handler needs to handle them differently. You can provide more specific information, to the programmer at least, by supplying a suitable message string with the exception.
Contributors: WilliamGrosso, DaveHarris, many others
I also think it is OK to use silent exceptions for RapidPrototyping, as long as you don't ShipThePrototype. That is, you can use it to reduce the scope of one refactoring session, provided you rename it in another refactoring session shortly later. -- DaveHarris
I'm confused (but remember, I'm not pro-exception). If the bloody things are exceptional, what is the value of investing in creating new classes to represent them, compared to just throwing the generic Exception with the quoted specific description? It seems to me that generally the system is coming down anyway, and the last thing you'll see will be the message.
Whether the system is coming down anyway depends on the particular condition and whether it can be handled programmatically. For example, opening a cache file and getting a FileNotFoundException? doesn't bring the system down if the appropriate action is to create a new, empty file.
Exceptions are thrown in exceptional situations, not necessarily in apocalyptic situations where the program is sure to die a horrible death. They are often very helpful for allowing your app to continue running, while letting the user know that an exceptional situation has arisen that he should pay attention to. Maybe the user entered some bad input, give him a message dialog telling him to go fix it before moving on. This has been helpful to me. I would rather catch a SAXParseException and tell the user "Hey, you didn't close the bracket on that last xml tag! Go fix it before updating the tree view", than catch an Exception and tell the user "Exception occurred: Application will shutdown. Unsaved work will be lost. Have a nice day."
Or ... are we also going to have some complex exception analyzer somewhere going through complex logic to see whether it can recover some or all of them?
Help me get inside the value of doing all this stuff? -- RonJeffries
Exceptions allow you to keep return values clean. Your return values don't also have to contain out-of-band conditions. In our system, we have a thing called a MultiValidationException? (potentially containing many validation errors). Our various methods return a validated value object, or throw an exception. We don't need to check return values to see if validation succeeded, so the code is much cleaner looking.
I'm in between your argument and the starting argument. See GeneralizeOnExceptionBehavior. -- RobertDiFalco
The only possible value for a non-generic exception is in the case where a problem could not be prevent, but it could be recovered from, with the further qualification that the recovery decision cannot be made at the point the problem is detected. The only set of problems where I see any value in having recovery modes are in multi-machine systems. In these cases, it can be simply too expensive (in terms of overhead and response time) to verify the state of a remote machine prior to each access, and depending upon latencies, a non-trivial window of failure may still exist between the check and operation. For operations hosted on a single machine, the machine needs to be treated as a unit; if the hard drive fails, retrying at an application level is pointless. In general, handle transient problems proactively (prevent them, don't throw exceptions after the fact), and reserve exceptions for failures. As a side note, please, please, please put a good diagnostic message into an exception when thrown. The message should be dynamically created to contain as much run-time information about the problem as possible. This message may be your last, best hope for isolating a field reported error. -- WayneMack
In general, you should not have exception-handling logic that switches on the type of the exception as part of your application's flow of control. It works against the out-of-band property of exceptions. Exception handling logic is best kept orthogonal to the rest of your application.
So throwing pretty generic exceptions is just fine and dandy in my book. By "generic", I mean a custom base exception that's one-level-derived from your language's base application exception class: java.lang.RuntimeException in Java, System.ApplicationException? in .NET .
So why have different exception types at all?
1) Because sometimes you can add context and rethrow an exception with more information
An example: consider a generic type that can hold copies of itself, i.e. a CompositePattern. You might be several levels down, parsing such a thing, when you hit an error. Throw an exception that carries information about where you are in the object. The catch clause at the top of the parsing logic looks for that exception, and can then use the additional context (e.g. the original variable that was passed) to construct and rethrow an exception with a more informative error message.
The upshot is that you get an error message looking like this:
"instrument.sides(1).flows(20).reset.day_count_factor: not a string"
as opposed to this:
"day_count_factor: not a string".
So one point where you might want to use exception-type-based logic is in exception-generation/rethrow code.
2) Because sometimes you want to distinguish between subsystems
I contribute C++ analytics to a whole bunch of systems, about 20, in a variety of languages and on a variety of platforms. When writing bindings for a given language, we have found it useful to have a base type for our exceptions (derived from whatever the local type system's base application exception class is) that is our own. Then, if there's a problem, people can tell instantly if it's from their code or our code.
Now we are getting a larger code base, we are experimenting with having an exception subtype per major subsystem inside our own code too. This is for much the same reason, e.g. easy identification of error source.
All this makes it sound like we have loads of exception types. But we don't. We have 8 for hundreds of thousands of lines of code. Most of the time, given the caveats above, a single type with textual description will meet your needs.
In response to RonJeffries question of seeing the value of creating new classes to represent exceptions, I have found it fairly valuable to do this while UnitTesting. Having specific exception classes for each exceptional scenario, can help avoid false positives in testing. Let's say you have a UnitTest that that tests for an exception, such as follows.
public void testDoSomething() {
try { doSomething(); fail("Didn't throw IllegalArgumentException"); } catch ( InvalidArgumentException e ) { ; //we expect to get here }}
If the code triggered by doSomething() throws an IllegalArgumentException for a reason other than what you are testing, then your test will still pass and thus give you a false positive. This can be avoided by creating a very specific exception for each exceptional scenario.
One fairly clean way to do this is to do a public inner-class with a private constructor:
public class MyClass {
... ... public class void MySpecificException extends RuntimeException { private MySpecificException() {}; }}
That way, only MyClass can create the exception, but your unit tests can test that it was thrown.
-- JavidJamae
I think the word complex is a bit over-used in Ron Jeffries's statement. Avoid complexity whenever possible (but no oftener).
Consider writing to a database. I'm about to try and update some chunk of the database. This can fail in a number of ways.
We use exceptions for this for the following reasons:
So, fine, you say. I'll use an exception (okay, you don't say this. But some of us do). Now the question is: can you get away with just throwing a generic exception and put all in the information in a string.
Yes, you can. And you should do it. Then, when you're done, gather up the strings. There'll probably be a handful of them, and it'll be pretty obvious how to arrange them in an object hierarchy (e.g. RefactorToSpecifyExceptions?).
The claim is that you should do this refactoring. Why?
I agree. This also follows YouArentGonnaNeedIt. Until one of the callers needs to discriminate between different problems, don't make a class hierarchy. When I'm developing in c++ I often find myself throwing a string, for the same reason. Until I do something other than catching a string at the end of main, I don't need any new classes. -- DaveWhipp
[Aside consider throwing std::exception rather than a string (char * ?)]
I understand the point of refactoring, but I disagree about how it should be handled. Overloading the message of an Exception seems to be a little silly to me. Rather than do that I would create a MetaException? which contains an array of Exceptions. Then I can keep all the real Exceptions still only have one catch block. But this approach, in my mind, is over complicated.
A simpler way to do it is to simply *catch* a generic exception (the code in the try can throw many different exceptions). If there is a need to handle one specific exception in a specific way (it might be recoverable), but handle all other exceptions in a specific way, simply catch the specific exception first and then catch Exception.
This has several advantages: 1) The exception throwing code is very simple, 2) exceptions are still strongly typed, 3) the structure is still flexible enough so that the catcher can deal with exceptions either specifically or generically.
-- Paul Philion
RonJeffries made an assertion up there that "generally the system is coming down anyway" when an exception is being thrown. I think that assumption needs to be addressed head-on. In general that isn't true instead, ExceptionsCancelTransactions. If the operation is critical to the system then it is reasonable to shut the system down if the operation fails. In many cases, however, all that is needed is for the resources that were allocated to that operation to be released and for the user to be notified that her request couldn't be satisfied. The nice thing about exceptions is that they provide a mechanism for the operation to take responsibility for cleaning itself up while placing responsibility for how to handle the failure on the client.
Having a hierarchy of exception types and throwing the most specific type possible allows the operation to provide information to the client at exactly the level of granularity that the client needs -- without knowing beforehand what that granularity is. -- PhilGoodwin
Indeed that is the question ("the system is coming down anyway" vs. "exceptions cancel operations"). Exception handling is simply another control structure, as are goto, break, if, loop. Someone named it 'exception handling' to imply something about how they thought to use it, having invented it. We are under no obligation to agree with that person, even if we could figure out what that person meant by "exception".
I have always thought of an exception as a Really Big Thing, possibly from the name and from its resemblance to a goto. I have to keep all kinds of things in my head when I use an exception, and it permeates the code. So I basically don't like them. The current proliferation of exception-based code is getting me to examine my views, and all this discussion helps - so thanks. I would only suggest that we not be bound by what someone else maybe meant by the term, and instead look at whether we think we and the code are better off for having many exceptions.Thanks for all the writing -- AlistairCockburn
My experience with decent exception systems (i.e. not including C++) is that exception types end up being grouped by library, so you don't need to end up with an explosion of catch blocks -- unless you're really interested in one particular area. For example, in a stream API you might want exceptions for failure (e.g. the underlying disk crashed), errors (you wrote to a closed thread), and thread interrupts. The thing about checked exceptions is that they tell you what may go wrong when you call a method and, if you listen, make you think about what to do in those cases. With unchecked exceptions, I can't tell from the code whether there's another route out of my block. I think there's a pattern here on the lines of LetTheTypeSystemDoTheWork?
Two other points. One of the many things that Java didn't quite get right was not allowing people to mark checked exceptions as fatal errors (i.e. we shouldn't have got here so we better stop now ). My approach, which is bad Java manners, is to create an unchecked FatalError?, wrap any such exceptions in one, and rethrow. This stops the program, but also marks the exception as something that's my fault and gives me a place for a breakpoint. Second, some languages, including Java I believe, expect exception throws to be infrequent and optimize accordingly -- that is, try/catch blocks are cheap but exception throws take a lot of reorganization. -- SteveFreeman
Are you using unchecked exceptions in places where you would have used assert? I'm thinking of this sort of code:
switch (x) { case 1: ...; break; case 2: ...; break; case 3: ...; break; default: assert (false); }Wrapping checked exceptions in an untyped exception and re-throwing them is Pretty Bad Manners, but if you're doing asserts, an untyped exception is the right thing to use.
Exceptions are simple. I don't know what the fuss is about. Unless you are going to argue that no method or function is ever going to have to return an error, ever, your software has to have some way to flag error conditions.
Returning "null" is a bad idea; especially if null itself might be a valid value. So the number one benefit is that exceptions raise errors OutOfBand. This way you will never accidentally pass around an error flag as though it were a value.
The second benefit is that exceptions force you to deal with error cases. Programmers are lazy and often in a hurry; they don't notice or don't bother to check error cases. With exceptions, the compiler forces programmers to handle all the cases.
Throw a different type of exception for each error case you want to force the caller to handle.
That's all there is to it. Aside from this, exceptions are just like error values being returned from functions. And as was mentioned, the fact that a function couldn't do its job doesn't mean the whole system is coming down.
For example, if a webserver tries to write an HTML file to a client over a network connection after the client has given up and gone away, the whole server isn't going to come down. The stream will throw an IO exception and the server will free the resources associated with handling that request - but continue serving others.
You could do that with error flags instead, but people might ignore them, and you'll have to use a return value large enough to hold the error flags as well as the data (i.e.: an int where a char would do).
Use exceptions in exactly the same places where you would have returned an error flag.
-- JustinWells
In a layered system, the reason for using specific exceptions rather than generic ones is that is allows an exception to percolate up to the layer than can deal with it. Calling code should only catch exceptions that they know how to handle and let all others propagate up. This allows low level code to raise catastrophic failure exceptions which would be caught at a high level and dealt with there. If we only had generic exceptions, then we might have to deal with this exception situation in multiple places, violating the OnceAndOnlyOnce principle.
This is expressed better elsewhere as CatchWhatYouCanHandle and LetExceptionsPropagate.
For me, it is sometimes desirable to have a mix of subclassed exceptions and generic (untyped) exceptions. This is useful particularly in GUI based systems where there CAN'T BE ANY CATASTROPHIC CONDITIONS (you just can't quit the application, you have to try and recover and let the user know what is going on). However, this is the only place I use generic exceptions: For throwing the type of errors I expect someone to catch and display a message.
In general, all typed exceptions are caught and must be dealt with (can't open a file or URL? catch the exception, clean up, maybe throw another typed exception to work your way up and then eventually throw a generic exception with an appropriate message for the end user.) In this way, generic exceptions are reserved for encapsulating error messages appropriate for logging or end user notification.
For example:
void do_something_complex() throws an_alert_exception { try { do_something_very_weird(); do_something_simply_dangerous(); } catch (some_very_weird_exception e) { // fix what I can... throw new an_alert_exception("Can't do something that complex!"); } } void run() { try { do_something_complex(); do_other_stuff(); perhaps_do_whole_app_here(); } catch (an_alert_exception e) { display_alert_dialog(e.getMessage()); } }-- ToddCoram
I have to disagree with the second of these rules: Don't throw Exception itself.. Exception will do just fine in almost all situations. If you do need to throw more specific types of exceptions then do so, but don't ever declare anything other than "Exception" in your throws clause. That essentially means that your method signatures will indicate only whether or not the method allows exceptions to propagate, not the specific types of exceptions that propagate. This is just enough information to allow you to ensure program correctness but not so much that your methods become hopelessly coupled to each other. -- PhilGoodwin
[I think this page is due for some refactoring. Does anyone want to keep chatting or can I replace this page with a summary? -- pg]
Go for it Phil! Afterwards, it would be nice if you reported your experience on IrrevocableThreadMode.
Initially, I didn't feel strongly either way about throwing Generic exceptions or listing out each and every exception thrown by a method...until I started working on a project which adopted the following pattern to exception handling, in almost every method!
public void doSomething() throws Exception { try { } catch (ExceptionSubtype? e) { e.printStackTrace(); // or log it somewhere throw new Exception(); } }Now. I come to debug this code and look at stack traces dutifully supplied to me by users. None of the stack traces tell me where the code actually fell over because at each level exceptions were caught and new ones thrown. Worse, I didn't know what type of exception was being thrown so I can't even hazard a guess as to what the nature of the error was.
This is a particularly bad example but if the methods handled exceptions that the method could really cope with and leave the others then I would know what happened and where it happened.
Another issue with throwing general exceptions is that I cannot report the exception properly to a user - was it a problem with the database I was attempting a connection with, did the user not have sufficient privileges, etc etc. When using someone else's code that throws exceptions it is usually a good thing to know what to expect in the way of errors from that code - java.lang.Exception isn't enough.
Also, knowing exactly what type of exception is being thrown by a method on a class that someone else has written, means that I have a chance in my code to catch and deal with those exceptions, or choose what exceptions I can deal with.
Since working with code that throws generic exceptions everywhere I can report that debugging it is very slow, tedious and time consuming. It really is worth the 10 seconds or so it takes to type out the list of exceptions thrown by a method rather than simply Exception.
This is a fault of the strange information-hiding pattern above, not of the principle of throwing generic exceptions. If the pattern had been to just propagate exceptions as far as the interface, then log them and handle them, then your debugging would have been fine.
Yes you are quite right :-), my example is about information hiding and not about generic exception throwing. Perhaps this section should be deleted or moved elsewhere. -- ChanningWalton
RonJeffries asks, "If the bloody things are exceptional, what is the value of investing in creating new classes to represent them, compared to just throwing the generic Exception with the quoted specific description?"
Here's an example from a project I'm currently working on:
I am building some code (for the sake of discussion, I'll call it the Formatter) that reads and digests XML files that contain various bits of information, and spits out new XML files that incorporate that information into a different framework. There are various ways in which the process can fail. For example, the input XML file may be malformed, in which case the XML parser throws a fit. Or the input file is valid XML, but contains a structural error (e.g., a <bar> element inside a <foo> element, when that is not allowed) [Time out - if the xml is "valid", then there are no errors of that sort. Did you misspell "well-formed"? -- DanilSuits]. Or the text content of some element may not be in a proper format. And so on.
Any of these problems require that the formatting process be suspended for that file. (The Formatter does not have the authority to attempt to correct any of these problems on its own.) And since the problems may become evident at varying stages of the formatting process, it makes sense to raise exceptions to signal the error. That way, processing backs out to the outermost level, at which point the exception is dealt with. (The Formatter runs as a Windows NT service, and it must not crash, as that would prevent other users from sending it files, and that would be a Bad Thing.) When an exception is raised, the Formatter is responsible for creating what amounts to an error report that identifies the type of error, along with where and why it occurred. The report must also include some guidance for the poor user of the largely brain-dead system that creates the input XML files, so that said user can go back and fix the problem.
Naturally, the error message, the context in which the error occurred, and the "how to fix it" text are all part of the exception, so it makes sense to create a descendant exception class that has appropriate fields for these things. But wait, there's more: The form that the exception context takes can vary. For example, the context for an XML parser error is the line number and character position in the file where the error occurred. The context for an invalid child element is the traversal path through the XML node tree that arrived at the bogus element. Rather than give the exception-handling code the responsibility for dealing with all of these different contexts and knowing how to format them into the error report, I move that responsibility to the individual exception classes themselves. The code that raises the exceptions can create the exception and pass it the appropriate context, expressing that context in its "own language," so to speak. The exception-raising code doesn't need to know about how the error report is to be formatted, etc. -SteveSchafer
When different exceptions are handled differently, throwing specific exceptions makes sense. The question is whether it's better to throw generic exceptions when you have generic error handling.
Also, don't forget the exceptions builtin to the java data structure library, such as the NoSuchElementException and EmptyStack'Exception. These are great if you are doing some sort of strange dynamic key calculation for a hashmap or just taking a wild guess at the number of times to pop your stack, but for the most part, or at least in the programs I am accustomed to seeing, these sort of things are taken care of in the program itself. You don't just pop your stack until an emptiness exception is thrown. Generally, it is easy enough to find out how deep you are at any point. Imagine if C programmers were to start writing software that could catch a divide by 0 error and say "whoops, I guess that's the end of the loop".
But the annoying thing is that these methods within the data structures are declared as throwing these exceptions, and so they must be caught by the application or it won't compile. Often it isn't meaningful to catch an empty stack exception if you know exactly how many items are on your stack. Granted, in a multi-threaded application, it might get trickier to keep tabs on the state of a stack, but shared data structures are supposed to facilitate operations between threads, not hinder them. If it becomes that much of a problem, perhaps the approach needs to be rethought.
So when you're creating classes for use by other people, I think it is important to keep in mind what exceptions are going to be desirable vs. what exceptions are mandatory. If you throw an exception in your class that other people have to use, then they are then forced to catch that exception even if they don't need or want what it represents. Otherwise we might have people suddenly getting an ItsFiveOClockTimeToHeadHomeException and having to have their program catch it in order to keep working past five o clock.
NoSuchElementException and EmptyStackException are both subclasses of Runtime'Exception, and are thus unchecked, so you don't need to write throws or catch clauses for them.
Exceptions are going to happen in software, especially in more complex system. I have seen much code where a Builder or Mediator will coordinate multiple calls into different subsystems, which might throw a wide array of Exceptions. Lazy/inexperienced developers (in code I have seen) will choose to "hide" all the Exception complexity and simply throw Exception. This is bad.
In Java, declaring that a method throws Exception forces all calling methods to catch Exception. So, when the underlying code might really general a FileNotFoundException?, a MalformedURLException or a SocketException? (all things that can be potentially dealt with in-code, through user notification, retry, logging, etc.), that forced catch block will also pick up NullPointerException, ArrayIndexOutOfBoundsException, ClassNotFoundException and even ClassCastException.
So, while a system might be able to recover from a FileNotFound? exception, the handing for a NullPointerException should be completely different (IMHO). Declaring that a method "throws Exception" hides what exceptions are really thrown, and makes exception conditions much more difficult to deal with.
-- PaulPhilion
Even if you specify the kinds of exception a method may throw, you'll still have to handle NullPointerException someplace. What's wrong with handling it along with any other unexpected exception? Or are you writing code that throws NullPointerException on purpose and you want callers to have a separate catch for that? I don't think I've ever done that. -- EricHodges
I've been experimenting with using "throws Exception" until I need something more specific. I've found I rarely need anything more specific. My exceptions are generally dealt with at a few transaction control points. Catch clauses are rare inside the transactions. Exception types have more to do with the intent of code at the transaction control points than with the methods throwing the exceptions, so I don't see much benefit from specifying those types throughout the code. -- EricHodges
In C++, I have usually found it best to use generic exceptions (the std:Exception class) containing a very explicit, run-time generated error message. The design approach we usually take is based on error prevention, do not allow unacceptable data to be entered. Anything then caught is then limited to unexpected cases and no correction is available; we just display the error message to the user, perhaps log it, and end the current operation or perhaps the entire program. Having explicit error types does not help us much in tracking down problems, having as much detailed run-time information (nee "core dump") embedded as the text of the exception is worth a great deal. -- WayneMack
Our team's approach is to use exceptions for precondition violations, postcondition failures as well as what I would loosely call 'act of God exceptions' - i.e. exceptions caused by the external environment not conforming to an application's expectations. If we were using Java and not C++, we'd be using unchecked exceptions for the first two and checked exceptions for the third category, but instead we use three cosmic exception baseclasses from which all others derive. This turns out to be less of a problem than you might think.
As with JamidJamae?'s unit testing example above, we find it very useful to distinguish between flavours of exceptions solely to ensure that unit tests for precondition violation detection / act of God exceptions on a component don't get confused by propagation of unexpected exceptions up from the component's own internals and collaborators, which we regard as being genuine failures of these tests.
(Note the implication here - we are unit testing our precondition checking. This means we check that our DesignByContract stuff is working properly and it provides a concrete illustration of what the precondition really means without needing some additional assertion metalanguage.)
We do ConvertExceptions for act of God exceptions in the sense of adding context as an exception propagates up through higher-level tiers of the application - but apart from folding in more description and location information from each tier we aren't doing anything that justifies anything more specific than having a single act of God exception class (as this already copes with nested exception composition).
The reason for this lack of interest in exception categories at the package (or in our case namespace, as we are using C++) level is that we rarely need to write a line of exception handling code that would work differently depending on the precise exception runtime type. Nearly all of the handlers (with the exception of the precondition unit tests mentioned above) either add context and rethrow a composite exception up to the next level, or decide that the operation that threw the exception has been completely rolled back, in which case it is considered cancelled at that level - usually this is part of the user interface tier.
So yes, convert exceptions and add context, but the end product might as well be a generic act of God exception - because one would simply report what happened to the end-user and allow a retry, or abandon ship and terminate the application, or allow a heartbeat process to restart the whole shebang.
As for DesignByContract exceptions, these are not handled at all - we want to know about these failures asap when running our unit tests.
I'd be interested to hear from people who have definitely needed to switch on the runtime type of the exception in their handlers - what did this serve, other than possibly to provide different forms of report for each exception type?
Would this be better achieved by dynamic binding rather than type-switching? If the handler really takes remedial action based on exception type, wouldn't either approach violate information hiding - so shouldn't I use a continuation passed down by the client rather than an exception thrown up by the component - so would the continuation act like a semi-dispatched multimethod or partially applied curried function inside the component?
Or should I just stop worrying and throw a generic exception? :-)
Oh - one thing more: while we don't switch on exception types for act of God exceptions, we do for some special precondition violation exceptions. This is for very expensive precondition checks that are entwined with the operation itself. We take the view that it's worth bending the rules for these exceptions and using them as part of the primary logic of the application. Client code has to be prepared to handle these exceptions as part of the ordinary course of usage. In Java terms, these particular kinds of precondition exceptions would be checked. Nasty, but pragmatic!
Hmmm, I think I've just expanded on EricHodges' case in way too many words. Refactor my entry at will.
-- GerardMurphy
I found this page while searching for JavaGenerics and the advice applies there too. You shouldn't use generics when defining your exception classes.
I don't think Java will let you make a generic exception class like this:
class MyException<E> extends Exception { ... }Well, it might let you make it, but how would you catch it?
catch(MyException<Integer> mei) { ... }JavaGenerics uses TypeErasure, so you could not specify that MyException<Integer> as opposed to MyException<String> should be caught... that information is not available at runtime.