As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
Do you prefer checked exception handling like in Java or unchecked exception handling like in C# and why?
I think checked exceptions are a failed experiment. The original goal of exception was to eliminate the need to validate every function call return, which was resulting in programs programs that are difficult to read, and probably inefficient as well, thus discouraging programmers from signaling and handling exceptions.
While great on paper, in practice the checked exceptions reintroduced the very same problem exception were supposed to eliminate in the first place. They add a tightly coupling between the layers of application. They make it impossible for libraries to change their implementation in subsequent versions. The link posted by crausher goes into details and explain the problems much better than I ever could.
Meh.
Checked exceptions are a great thing when used properly, but more often than not they lead to stuff like:
doSomething();
try
{
somethingThrowsCheckedException();
}
catch(ThatCheckedException)
{ }
doSomethingElse();
And, frankly, that's just wrong. You should let exceptions you don't handle bubble up.
Checked exceptions used properly can be good. But very frequently, the result of doing checked exceptions properly is method signatures like this:
public void itMightThrow() throws Exception1, Exception2, Exception3, Exception4, // ...
Exception12, Exception13, /* ... */ Exception4499379874
{
// body
}
Am I exaggerating? Only slightly.
Edit:
That said, one thing I prefer about C# over Java when it comes to exception handling has nothing to do with checked exceptions (I can get that if I go with Spec# anyway). No, what I like is that the stack trace in C# is populated when you throw an exception, rather than when you instantiate one as it is in Java.
Edit 2: This is for the commenters #Yishai, #Eddie, #Bill K:
First, you should check out this thread for information on how to get a stack trace without instantiating an exception. Keep in mind that walking the stack is a heavy process and should not be done on a regular basis.
Second, the reason I like C#'s exception stack trace being populated at throwal rather than at instantiation is that you can do things like this:
private MyException NewException(string message)
{
MyException e = new MyException(message);
Logger.LogException(message, e);
return e;
}
// and elsewhere...
if(mustThrow)
{
throw NewException("WHOOOOPSIEE!");
}
That's a trick you can't do in Java without having the NewException method included in the stack trace.
I prefer checked exceptions for things that can go wrong that you cannot predict ahead of time. For example, IOException, or SQLException. It tells the programmer that they have to account for something unpredictable going wrong, they cannot write robust code that will not throw an exception, no matter how much they try.
Too many times programmers view a checked exception as a language thing to handle. It isn't (or won't be in a well designed API) - it is an indication that there is unpredictable behavior inherent in the operation, and you should rely on a deterministic result of the operation always working the same given the same inputs.
That being said, in practice checked exceptions suffered from two things:
Not all applications written in Java need that robustness. A compiler-level flag to turn off checked exceptions would be nice - although that could lead to APIs abusing checked exceptions when their developers work with the flag set to turn them off. After thinking about a better comprimise here, my current thinking is that a compiler warning is the best ballance here. If checked exceptions were compiler warnings, including a compiler warning if one was ignored several layers down (so the fact that one was ignored would be compiled into the class), so that the caller would at least know to catch Exception even if he couldn't know which one, then those who don't care would ignore the compiler warning, and those who do would not, without anyone being forced to write error handling code they don't care about to get their code to compile.
Exception chaining took much too long (version 1.4) to introduce. The lack of exception chaining caused a lot of bad habits to develop early, instead of everyone just doing:
throw new RuntimeException(e);
when they didn't know what to do.
Also, a checked exception is another API design element to potentially get wrong, and the users of the API have to suffer with the design flaw.
EDIT: Another answer points to two issues that motivated the C# design decision of no checked exceptions. To my mind, both of those arguments are very bad, so I thought they were worth addressing/counter balancing.
Versioning. The argument is that if you change your API implementation and want to add additional checked exceptions, then you break existing client code.
Scallability. Before you know it you have a method that throws 15 checked exceptions.
I think both versions suffer from the unaddressed point that when those remarks were made it was already accepted that the proper way to deal with a checked exception moving up to the next level would be by wrapping a different checked exception appropriate to the abstraction of your API. For example, if you have a storage API that could deal with IOException, SQLException, or XML related exceptions, a properly desgined API would hide those differences behind a general PersistanceException or something like that.
Besides that general design guidance, in the specific the arguments really lead to a lot of questions about the alternatives:
Versioning. So a developer developed against your database API, thinking that they caught and handled the relevant exceptions (say DatabaseException) and then you decide in the next version to add a NetworkException to capture network level communication issues with the database. Now you just broke all compatability with existing code, and the compiler won't even complain about it. Everyone gets to discover it in regression testing, if they are lucky.
Scalability. In the C# solution, if three API levels down there is a potential for access to a volatile resource, you are relying entirely on the API documentation, because the compiler won't tell you that.
That is a great design for web apps where dying and showing the user a nice error 500 page is about all anyone bothers doing (since transactions are handled by the container anyway). But not all applications are built with such requirements in mind.
The argument ends up boiling down (to me anyway): Don't worry about exceptions, anything can go wrong and just build a catch-all.
OK. That is the core difference between a checked and unchecked exception approach. The checked exception alerts the programmer to volatile unpredictable calls. The unchecked exception approach just assumes that all error conditions are of the same class, they just have different names, and they are made unchecked so that no one goes around catching them.
Now the arguments do have merit at the CLR level. I agree that all checked exceptions should be at the compiler level, not the runtime level.
I have never used Java, but since I read
Why doesn't C# have exception specifications?
Does Java need Checked Exceptions?
The Trouble with Checked Exceptions
I am quite sure I don't like checked exceptions (in the current implementation).
The two main points mentioned are the following.
Versionability
Anders Hejlsberg: Let's start with versioning, because the issues are pretty easy to see there. Let's say I create a method foo that declares it throws exceptions A, B, and C. In version two of foo, I want to add a bunch of features, and now foo might throw exception D. It is a breaking change for me to add D to the throws clause of that method, because existing caller of that method will almost certainly not handle that exception.
Adding a new exception to a throws clause in a new version breaks client code. It's like adding a method to an interface. After you publish an interface, it is for all practical purposes immutable, because any implementation of it might have the methods that you want to add in the next version. So you've got to create a new interface instead. Similarly with exceptions, you would either have to create a whole new method called foo2 that throws more exceptions, or you would have to catch exception D in the new foo, and transform the D into an A, B, or C.
Scalability
Anders Hejlsberg: The scalability issue is somewhat related to the versionability issue. In the small, checked exceptions are very enticing. With a little example, you can show that you've actually checked that you caught the FileNotFoundException, and isn't that great? Well, that's fine when you're just calling one API. The trouble begins when you start building big systems where you're talking to four or five different subsystems. Each subsystem throws four to ten exceptions. Now, each time you walk up the ladder of aggregation, you have this exponential hierarchy below you of exceptions you have to deal with. You end up having to declare 40 exceptions that you might throw. And once you aggregate that with another subsystem you've got 80 exceptions in your throws clause. It just balloons out of control.
In the large, checked exceptions become such an irritation that people completely circumvent the feature. They either say, "throws Exception," everywhere; or—and I can't tell you how many times I've seen this—they say, "try, da da da da da, catch curly curly." They think, "Oh I'll come back and deal with these empty catch clauses later," and then of course they never do. In those situations, checked exceptions have actually degraded the quality of the system in the large.
OK, I wasn't going to reply, but this is taking too long to get closed and got many answers on one side of the fence, so I feel the need to weigh in on the other side.
I support checked exceptions -- when properly used -- and believe that they are a Good Thing. I've heard all of the arguments above many times, and there is some merit in some of the arguments against checked exceptions. But on net, I think they are positive. Having programmed in C# and Java, both, I find C# programs are more difficult to make stable against Exceptions. The great thing about checked exceptions is that the JavaDoc is guaranteed to tell you that the Exceptions can be thrown from that method. With C#, you rely on the coder to remember to tell you what exceptions may be thrown from any given method, and also what exceptions may be thrown from any method called by that method, and so on.
If you want to create 5-9's reliable code, you need to know what exceptions can be thrown from code that you call, so you can reason about what can be recovered from and what must cause you to abandon what you are doing. If C#, you can do this, but it involves a lot of trial and error until you have seen all of the possible exceptions that can be thrown. Or you just catch Exception and do your best.
There are pros and cons to both approaches, that of Java and C#. Reasoned arguments can be made in favor of both, and against both. Again, on net, I prefer the approach chosen by Java, but were I to re-write Java today, I would change the APIs to change some checked exceptions into runtime exceptions. The Java API is not consistent in its use of checked exceptions. And as someone else said, it took far too long for Exception chaining to appear as a standard API feature and a part of the JVM.
However, the charges that are lain at the feet of checked exceptions too often fall into the category of, "lazy programmers misuse this language feature." That's true. But that's true of many languages and their features. The "lazy programmer" argument is a weak one.
Let's address the main complaints that don't fall into the "lazy programmer" bucket:
Versionability - yes, throwing a new Exception in a new version of your code will break compilation for clients who blindly drop in your new JAR file. IMO, this is a good thing (as long as you have a good reason for throwing an additional checked exception), because the clients of your library have to reason about what they need to do with this behavior change. If everything is unchecked, then your clients don't necessarily have any clue (until an Exception occurs) that your behavior has changed. If you are changing the behavior of your code, then it's reasonable for your clients to have to know about this. Have you ever updated to a new version of a 3rd party library only to find its behavior has invisibly changed and now your program is broken? If you make a breaking behavior change in your library, you should break automatic compatibility with clients using earlier versions of your library.
Scalability - If you handle checked exceptions properly by translating them to a specific checked (or unchecked) exception appropriate to your layer of the API, this becomes a non-issue. That is, if you code properly, this problem disappears. And doing so, you properly hide your implementation details, which your callers shouldn't care about anyway.
Too often, this is simply a religious issue with people, and that's why I get (unnecessarily, I know) irritated. If you have a religious aversion to checked exceptions, that's OK. If you have a reasoned argument against checked exceptions, that's OK. I've seen good reasoned arguments (that I mostly don't agree with, but still...). But mostly I see bad arguments against checked exceptions, including arguments which were fair and reasonable when talking about Java 1.0, but which are no longer applicable given modern releases of Java.
In practice it is better to use checked exception handling as it allows for more detailed information when your app begins flooding error logs at 2AM and you get a call to do some debugging...
In my opinion there exist cases where checked exceptions are appropriate. There are probably features that could be done differently in Java to better support them. It isn't without difficulties (for instance, in some situations you might want an exception checked, in others not). Java does, of course, support unchecked exception types as well.
The sort of exceptions that are suitable to be checked should generally be documented. The best place to document is in the code. The populist approach is just to botch it and only consider the happy case.
Checked exceptions are great as long as they are recoverable or not due to programming errors like an invalid index acces to a ResultSet. Otherwise they tend to pollute code layers and APIs by forcing the coder to declare things like IOException in many method signatures and giving nothing really useful to the client code.
I think in most cases checked exception are a waste of time. They entrap to things like the antipattern mentioned by randolpho or extensive creation of custom exceptions to decouple your implementation from used libraries.
Beeing rid of this 'feature' lets you focus on what you want to do.
The only thing I'dd like the compiler to check for me is whether a function throws exceptions or not. What specific exceptions that can be thrown doesn't matter. The thing is that in my experience, there are a lot functions that don't throw anything, and it would be nice if this was documented in the function specification. For these functions you don't have to worry about exception handling.
Related
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 7 years ago.
Improve this question
I wonder, why Microsoft developers do not provide us with "Try" versions of unreliable methods everywhere?
If I use a database connection or a smtp client I always must consider exceptions:
try
{
smtpClient.Send(message);
}
catch (SmtpException)
{
// test with real smtp server and analyze an exception and it's contents here
}
But what I want as a user is:
if(!smtpClient.TrySend(message, out reason))
{
// analyze reason here
}
And the biggest problem for me is an exception performance overhead. I just can't afford throwing exceptions on each client call of my service. If I need to check dozens of connections/providers this can cause dozens of exceptions per each client request.
My question is: what is the rationale behind such API design decisions in .NET? I don't think that this is an error, because it is everywhere, not in a single technology.
UPDATE
I must give you another example of an exception in .NET to stop talking about network delays. System.Diagnostics.EventLog.WriteEntry method can throw System.ComponentModel.Win32Exception if windows service is stopped, for example.
I wonder, why Microsoft developers do not provide us with "Try" versions of unreliable methods everywhere?
Since I'm not a Microsoft employee, I can only guess. And my guess is that this has two reasons:
They didn't think of it when designing the first version of the .NET Class Library -- note that the TryParse methods have been added in later versions.
The performance difference is not important enough (see below) to warrant the cost of implementing and maintaining the new Try... methods. There are other things that the .NET Framework needs more urgently.
And the biggest problem for me is an exception performance overhead.
I seriously doubt that. The "performance overhead" of an SMTP timeout (= a few seconds) dominates the "performance overhead" of throwing an exception (less than a millisecond) by more than a factor of 1000.
Considering that you are calling a network-based service, the cost of throwing the exception per se is not what is killing the performance. It is the cost of finding out when to throw an exception that is the culprit: the system needs to attempt a network call, wait for it to time out or return a failure, and only then throw an exception.
The cost of actual throwing is minimal, so providing a Try method would not help you improve performance. It may, however, help you improve readability, which is not a small thing. To that end, you could write your own Try wrapper / extension method, and hide catching of the exception inside it:
public static bool TrySend(this SmtpClient client, object message, out Error reason) {
try {
client.Send(message);
reason = null;
return true;
} catch (SmtpException ex) {
reason = ex.Reason;
return false;
}
}
OK, you do not see the point of exceptions yet. What you are suggesting (a Try... version for everything) basically defeats the point of exceptions entirely. The beauty of exceptions is that you do not NEED to check results for each and every method call. You just assume everything will succeed (the regular case) and if one call fails it will be "caught" and handled at a predetermined place in your call stack. Your code will be ever so much more readable because it only has the steps that matter, not the plumbing. Try... is nice for scenario's that are more likely/common to "fail" and are not really errors or problems but rather just part of the normal flow control logic.
Exceptions are the OO-way, returning error codes is old school. Think about a deeply nested call hierarchy and the responsibility to handle error codes at all levels and deal with them appropriately. Compare that to using exceptions. Are you seeing the light yet? :-).
The exception performance overhead is negligible in compare to the send / database operation you are performing.
Therefore there are scenarios (like these) that supporting the TryParse pattern is somewhat not needed.
And if you are in a scenario where you have "dozens of connections/providers" that cause "dozens of exceptions" it might be worth to check why it happens, could be a global problem with your smtp server.
P.S. Disclosure I am a Microsoft Employee, but I would answer you the same even if I was working in let's say Apple or Google :)
The main reason you don't see Try methods more often is that an exception communicates something. An "exceptional" condition occurs, and something must deal with it. The operation you just performed is so important that failure should cause the entire process to shut down. The method throwing the exception cannot handle this condition, and throwing the exception forces some block of code to handle this.
A network call is pretty critical to the successful function of your application, most times, so exceptions are appropriate. Furthermore, exceptions contain a message and the stack trace, which are essential in debugging the failure. Your proposed solution strips critical debugging information. This is not always critical, as with parsing an int, especially when it's often easy to recover from that error.
A failed network call or write to a disc is a whole different beast.
The question is certainly justified. Taking Eric Lippert's blog entry on exceptions as a basis and given that you took the necessary precautions to make sure that Send fails because of some network condition (and not because you passed invalid arguments somewhere), I would classify SmtpException as exogenous - like File.Open, there's probably nothing you can do to prevent it. Because of this, I would not classify the SmtpException as vexing, it's not the result of bad design choices (like int.Parse).
Make sure that an SmtpException, indeed, indicates something exceptional, and exceptions will be an appropriate tool. The overhead is, like others said, negligible.
My exception handling skills are very primary and I am always very confused about the way I should use them, not so much of the how/syntax. I am currently using C# (if there would be different things applicable to it).
My question is that what are the benefits of creating your own Exception class while developing an application? In comparison to throwing a standard Exception class exception. Basically what is a healthy practice of exceptions in your application.
Or if not benefits, then disadvantages?
By creating your own exceptions you can often create a more meaningful message (or more application specific type of message) for the end user, while still wrapping the original message, so as not to lose any useful information.
There is a great book by Bill Wagner that covers some reasoning about when you should or should not create your own exceptions along with some good practices for exception handling in general. Here is a small excerpt:
Your application will throw exceptions -- hopefully not often, but it
will happen. If you don't do anything specifc, your application will
generate the default .NET Framework exceptions whenever something goes
wrong in the methods you call on the core framework. Providing more
detailed information will go a long way to enabling you and your users
to diagnose and possibly correct errors in the field. You create
different exception classes when different corrective actions are
possible and only when different actions are possible. You create
full-featured exception classes by providing all the constructors that
the base exception class supports. You use the InnerException property
to carry along all the error information generated by lower-level
error conditions.
If there is a specific type of problem unique to your application that will call for a unique recovery strategy at a higher level in your application, you should create your own exception type so you can recognize and recover from that sort of problem optimally.
If the error is more of a "the caller did something wrong" variety, use the standard exception classes.
If you think your library is going to be long-lived and valuable, I would err on the side of creating your own exception classes, so that future users of your library can fashion their own recovery strategy.
Sometimes you want to do diffrent things for diffrent types of error, for example if a user inputs bad data it dosent make sence to crash the whole application and email the administrator. It would make sence to do that for a more serious exeption such as a stack overflow. You would then impliment diffrent catches depending on the type of error.
If a method is documented as throwing some particular class of exception in some particular circumstance, it should ensure that there's no way any exception of the class can bubble up through it in other circumstances. In many cases, the most practical way to ensure this may be to create a custom exception class.
Actually, I would regard much of the exception hierarchy as being pretty useless, and would suggest focusing on a fairly small number of exceptions, from which nearly all good exceptions should derive.
CleanFailureException -- The indicated operation could not be performed for some reason, but has not altered any object's state. There is no reason to believe any object's state is corrupt except to the extent implied by the operation's failure. This should be the type of exception thrown by a DoSomething method if a TrySomething method would return False. May in some cases be wrapped in a more severe instruction, if a failed operation leaves one or more objects in partially-altered or inconsistent states.
StateDisturbedException -- The indicated operation could not be completely performed for some reason, but may have been partially performed. The object on which an action was being performed has a state which complies with its own invariants, but may or may not comply with caller's expectations of it. Caller may attempt to use the object only after examining it and making sure it complies with expectations (changing it as needed). Alternatively, this exception should be caught at the point where the target object would no longer exist, and then wrapped in a CleanFailureException.
TargetStateCorruptException -- The indicated operation could not be performed because the particular object being acted upon is corrupt, but there is no particular reason to expect that corruption extends outside the object. This exception should be caught at the point where the target object would no longer exist, and then wrapped and replaced with CleanFailureException.
ParentStateCorruptException -- The indicated operation could not be performed because some object which the target's documentation would regard as a "parent" object is corrupt. Catch at the level where the corrupt parent objects would no longer exist, then wrap in a "CleanFailureException".
SystemOnFireException
While it may be nice to have exception names that indicate the nature of what went wrong, from a catching perspective what matters is whether one can safely catch and resume. Any exception hierarchy should focus on the latter issues, rather than the former. If the goal is to inform people of what went wrong, that should be done in Exception.Message.
The main benefits are to add information, so exceptions are more meaningful and thus allowing to catch exceptions that are specific to your application.
Throwing an exception is actually a more expensive operation than quietly failing, such as returning a bool. This question highlights what I mean:
How much more expensive is an Exception than a return value?
If you're writing something that you anticipate other developers are going to be using in their own project, then sure, an exception could be useful for them to make sure they're using your code right. Otherwise, if you're just using it within your own codebase, I would make sure to quietly fail.
One example where custom exceptions work well is when you are expecting external applications to interface with your project.
For example, if you had a small project that sends out an email it might make sense to throw a custom 'TooFewRecipients' error if you had a hard limit on the minimum number of recipients that must be emailed.
Custom exceptions will in general inherit from System.Exception
Remember that Exceptions should only be used for exceptional cases which your project can't handle in any other way, and they should be understandable enough to aid a 3rd party developer understand the issue. There is more information at MSDN
I know that this probably doesn't really matter, but I would like to know what is correct.
If a piece of code contains some version of throw new SomeKindOfException(). Do we say that this piece of code can potentially raise an exception? Or throw an exception?
The keyword is throw, so I am kind of leaning towards that, but to raise an exception is also used a lot...
Do they have some sort of different meaning? Does one of them sort of implicate a difference over the other? Or is it just two words meaning exactly the same thing?
In C# terminology, raising is used in the context of events and throwing is used in the context of exceptions.
Personally, I think throw/catch combination is more beautiful than raise/catch.
I can't speak for C#, but in C++ "throw" was chosen because "raise" was already taken as a standard function name.
I think while throw is the better one, the two terms are interchangeable. Very useful if you have to use it twice in some text so that you avoid repeating the same word. But that's stylistics which is not necessary for technical writing (but still a nice thing to have).
The terminology of the various languages favors 'throw'. And I agree that 'throw' makes a lot more sense considering this is the keyword used and the compiler/language documentation always refers to exception being 'thrown'.
However, in the belly of the behemoth exceptions are actually Raised, not thrown. If you find yourself deep enough in debugger staring at an EXCEPTION_RECORD then you talk in the terminology of SEH, in which the particular class of compiler/language exceptions (eh, clr, vcpp) is just one of the many flavors exceptions come as. I guess the original conditions for which exceptions where raised for, like page faults and stack overflows, were conditions 'noticed' by the kernel that was 'informing' the user mode of the condition and not exception the user code was 'throwing' onto himself, so the term makes more sense in that context.
Either throw or raise seems fine, they mean the same to me. I wouldn't write it, but when I'm talking, I usually say 'chuck an exception'.
For events I'd use either 'fire an event' or 'raise an event'.
Java has compiler checked exceptions. When I made transition to C++, I learned it doesn't feature checked exceptions. At first, I kept using exception handling, because it's a great feature. However, after a while I abandoned it, because I got into a situation every function might throw an exception. As only a small percentage of the functions I write can throw exceptions (say some 25% at the most), I found the overhead of doing exception handling for functions that cannot throw anything unacceptable.
Because of this, I am really surprised that there are a lot of developers who prefer unchecked exceptions. Therefore, I am curious to know how they handle this problem. How do you avoid the overhead of doing unnecessary exception handling in case the language doesn't support checked exceptions?
Remark: My question equally applies to C++ and C#, and probably to all other languages that don't feature compiler checked exception handling.
Simple. You don't do exception handling in "every function that might throw" - in C++, just about every function might do so. Instead, you do it at certain key points in your application, where you can produce a sensible, application-specific diagnostic and take sensible, application-specific corrective action, although use of the RAII idiom means (as avakar points out in his answer) that there is often little corrective action to be taken.
When I first started using C# I was scared by this too. Then I found that actually, it doesn't matter very often. I very rarely find that I can catch an exception and so something useful with it anyway... almost all my exceptions bubble up to somewhere near the top of the stack anyway, where they're handled by aborting the request or whatever.
Now when I'm writing Java, I find checked exceptions intensely frustrating a lot of the time. I think there's value in there somewhere, but it introduces as many problems as it solves.
Basically, I think we haven't really got the whole error handling side of things "right" yet, but on balance I prefer the C# approach to the Java approach.
In addition to what Neil said, you should note that there is no need for try/finally (or in context of C++ try/catch/throw), because object destructors are called even if an exception is thrown.
It is easily possible to have exception-safe code with very few try statements.
For C++ specifically, the overhead pretty much goes away if you design your classes well and use RAII.
Martin York has written a wonderful example of that in this answer.
The function can stll throw an exception, yes, but if it does, it won't need to do anything special to clean up. So you only need to actually catch the exception in one place -- the function that is able to handle it and recover from the error.
Unchecked exceptions are alright if you want to handle every failure the same way, for example by logging it and skipping to the next request, displaying a message to the user and handling the next event, etc. If this is my use case, all I have to do is catch some general exception type at a high level in my system, and handle everything the same way.
But I want to recover from specific problems, and I'm not sure the best way to approach it with unchecked exceptions. Here is a concrete example.
Suppose I have a web application, built using Struts2 and Hibernate. If an exception bubbles up to my "action", I log it, and display a pretty apology to the user. But one of the functions of my web application is creating new user accounts, that require a unique user name. If a user picks a name that already exists, Hibernate throws an org.hibernate.exception.ConstraintViolationException (an unchecked exception) down in the guts of my system. I'd really like to recover from this particular problem by asking the user to choose another user name, rather than giving them the same "we logged your problem but for now you're hosed" message.
Here are a few points to consider:
There a lot of people creating accounts simultaneously. I don't want to lock the whole user table between a "SELECT" to see if the name exists and an "INSERT" if it doesn't. In the case of relational databases, there might be some tricks to work around this, but what I'm really interested in is the general case where pre-checking for an exception won't work because of a fundamental race condition. Same thing could apply to looking for a file on the file system, etc.
Given my CTO's propensity for drive-by management induced by reading technology columns in "Inc.", I need a layer of indirection around the persistence mechanism so that I can throw out Hibernate and use Kodo, or whatever, without changing anything except the lowest layer of persistence code. As a matter of fact, there are several such layers of abstraction in my system. How can I prevent them from leaking in spite of unchecked exceptions?
One of the declaimed weaknesses of checked exceptions is having to "handle" them in every call on the stack—either by declaring that a calling method throws them, or by catching them and handling them. Handling them often means wrapping them in another checked exception of a type appropriate to the level of abstraction. So, for example, in checked-exception land, a file-system–based implementation of my UserRegistry might catch IOException, while a database implementation would catch SQLException, but both would throw a UserNotFoundException that hides the underlying implementation. How do I take advantage of unchecked exceptions, sparing myself of the burden of this wrapping at each layer, without leaking implementation details?
IMO, wrapping exceptions (checked or otherwise) has several benefits that are worth the cost:
1) It encourages you to think about the failure modes for the code you write. Basically, you have to consider the exceptions that the code you call may throw, and in turn you'll consider the exceptions you'll throw for the code that calls yours.
2) It gives you the opportunity to add additional debugging information into the exception chain. For instance, if you have a method that throws an exception on a duplicate username, you might wrap that exception with one that includes additional information about the circumstances of the failure (for example, the IP of the request that provided the dupe username) that wasn't available to the lower-level code. The cookie trail of exceptions may help you debug a complex problem (it certainly has for me).
3) It lets you become implementation-independent from the lower level code. If you're wrapping exceptions and need to swap out Hibernate for some other ORM, you only have to change your Hibernate-handling code. All the other layers of code will still be successfully using the wrapped exceptions and will interpret them in the same way, even though the underlying circumstances have changed. Note that this applies even if Hibernate changes in some way (ex: they switch exceptions in a new version); it's not just for wholesale technology replacement.
4) It encourages you use different classes of exceptions to represent different situations. For example, you may have a DuplicateUsernameException when the user tries to reuse a username, and a DatabaseFailureException when you can't check for dupe usernames due to a broken DB connection. This, in turn, lets you answer your question ("how do I recover?") in flexible and powerful ways. If you get a DuplicateUsernameException, you may decide to suggest a different username to the user. If you get a DatabaseFailureException, you may let it bubble up to the point where it displays a "down for maintenance" page to the user and send off a notification email to you. Once you have custom exceptions, you have customizeable responses -- and that's a good thing.
I like to repackage exceptions between the "tiers" of my application, so for example a DB-specific exception is repackaged inside of another exception which is meaningful in the context of my application (of course, I leave the original exception as a member so I don't clobber the stack trace).
That said, I think that a non-unique user name is not an "exceptional" enough situation to warrant a throw. I'd use a boolean return argument instead. Without knowing much about your architecture, it's hard for me to say anything more specific or applicable.
See Patterns for Generation, Handling and
Management of Errors
From the Split Domain and Technical Errors pattern
A technical error should never cause a
domain error to be generated (never
the twain should meet). When a
technical error must cause business
processing to fail, it should be
wrapped as a SystemError.
Domain errors should always start from a
domain problem and be handled by
domain code.
Domain errors should
pass "seamlessly" through technical
boundaries. It may be that such errors
must be serialized and re-constituted
for this to happen. Proxies and
facades should take responsibility for
doing this.
Technical errors should
be handled in particular points in the
application, such as boundaries (see
Log at Distribution Boundary).
The
amount of context information passed
back with the error will depend on how
useful this will be for subsequent
diagnosis and handling (figuring out
an alternative strategy). You need to
question whether the stack trace from
a remote machine is wholly useful to
the processing of a domain error
(although the code location of the
error and variable values at that time
may be useful)
So, wrap the hibernate exception at the boundary to hibernate with an unchecked domain exception such as a "UniqueUsernameException", and let that bubble up all the way to the handler of it. Make sure to javadoc the thrown exception even though it isn't a checked exception!
Since you're currently using hibernate the easiest thing to do is just check for that exception and wrap it in either a custom exception or in a custom result object you may have setup in your framework. If you want to ditch hibernate later just make sure you wrap this exception in only 1 place, the first place you catch the exception from hibernate, that's the code you'll probably have to change when you make a switch anyway, so if the catch is in one place then the additional overhead is almost zilch.
help?
I agree with Nick. Exception you described is not really "unexpected exception" so you should design you code accordingly taking possible exceptions into account.
Also I would recommend to take a look at documentation of Microsoft Enterprise Library Exception Handling Block it has a nice outline of error handling patterns.
The question is not really related to checked vs. unchecked debate, the same applies to both exception types.
Between the point where the ConstraintViolationException is thrown and the point, where we want to handle the violation by displaying a nice error message is a large number of method calls on the stack that should abort immediately and shouldn't care about the problem. That makes the exception mechanism the right choice as opposed to redesigning the code from exceptions to return values.
In fact, using an unchecked exception instead of a checked exception is a natural fit, since we really want all intermediate methods on the call stack to ignore the exception and not handle it .
If we want to handle the "unique name violation" only by displaying a nice error message (error page) to the user, there's not really a need for a specific DuplicateUsernameException. This will keep the number of exception classes low. Instead, we can create a MessageException that can be reused in many similar scenarios.
As soon as possible we catch the ConstraintViolationException and convert it to a MessageException with a nice message. It's important to convert it soon, when we can be sure, it's really the "unique user name constraint" that was violated and not some other constraint.
Somewhere close to the top level handler, just handle the MessageException in a different way. Instead of "we logged your problem but for now you're hosed" simply display the message contained in the MessageException, no stack trace.
The MessageException can take some additional constructor parameters, such as a detailed explanation of the problem, available next action (cancel, go to a different page), icon (error, warning)...
The code may look like this
// insert the user
try {
hibernateSession.save(user);
} catch (ConstraintViolationException e) {
throw new MessageException("Username " + user.getName() + " already exists. Please choose a different name.");
}
In a totally different place there's a top exception handler
try {
... render the page
} catch (MessageException e) {
... render a nice page with the message
} catch (Exception e) {
... render "we logged your problem but for now you're hosed" message
}
You can catch unchecked exceptions without needing to wrap them. For example, the following is valid Java.
try {
throw new IllegalArgumentException();
} catch (Exception e) {
System.out.println("boom");
}
So in your action/controller you can have a try-catch block around the logic where the Hibernate call is made. Depending on the exception you can render specific error messages.
But I guess in your today it could be Hibernate, and tomorrow SleepLongerDuringWinter framework. In this case you need to pretend to have your own little ORM framework that wraps around the third party framework. This will allow you to wrap any framework specific exceptions into more meaningful and/or checked exceptions that you know how to make better sense of.
#Jan Checked versus unchecked is a central issue here. I question your supposition (#3) that the exception should be ignored in intervening frames. If I do that, I will end up with an implementation-specific dependency in my high-level code. If I replace Hibernate, catch blocks throughout my application will have to be modified. Yet, at the same time, if I catch the exception at a lower level, I'm not receiving much benefit from using an unchecked exception.
Also, the scenario here is that I want to catch a specific logical error and change the flow of the application by re-prompting the user for a different ID. Simply changing the displayed message is not good enough, and the ability to map to different messages based on exception type is built into Servlets already.
#erikson
Just to add food to your thoughts:
Checked versus unchecked is also debated here
The usage of unchecked exceptions is compliant with the fact they are used IMO for exception caused by the caller of the function (and the caller can be several layers above that function, hence the necessity for other frames to ignore the exception)
Regarding your specific issue, you should catch the unchecked exception at high level, and encapsulate it, as said by #Kanook in your own exception, without displaying the callstack (as mentionned by #Jan Soltis )
That being said, if the underlying technology changes, that will indeed have an impact on those catch() already present in your code, and that does not answer your latest scenario.