Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

My specific case here is that the user can pass in a string into the application, the application parses it and assigns it to structured objects. Sometimes the user may type in something invalid. For example, their input may describe a person but they may say their age is "apple". Correct behavior in that case is roll back the transaction and to tell the user an error occurred and they'll have to try again. There may be a requirement to report on every error we can find in the input, not just the first.

In this case, I argued we should throw an exception. He disagreed, saying, "Exceptions should be exceptional: It's expected that the user may input invalid data, so this isn't an exceptional case" I didn't really know how to argue that point, because by definition of the word, he seems to be right.

But, it's my understanding that this is why Exceptions were invented in the first place. It used to be you had to inspect the result to see if an error occurred. If you failed to check, bad things could happen without you noticing.

Without exceptions every level of the stack needs to check the result of the methods they call and if a programmer forgets to check in one of these levels, the code could accidentally proceed and save invalid data (for example). Seems more error prone that way.

Anyway, feel free to correct anything I've said here. My main question is if someone says Exceptions should be exceptional, how do I know if my case is exceptional?

share|improve this question
3  
possible duplicate? When to throw an exception. Though it was closed there, but I think it fits here. It's still a bit of philosophy, some people and communities tend to see exceptions as a kind of flow control. –  thorsten müller Jan 24 '13 at 8:58
7  
When users are dumb, they provide invalid input. When users are smart, they play by providing invalid input. Therefore, invalid user input is not an exception. –  mouviciel Jan 24 '13 at 12:10
7  
Also, don't confuse an exception, which is a very specific mechanism in Java and .NET, with an error which is a much more generic term. There's more to error handling than throwing exceptions. This discussion touches on the nuances between exceptions and errors. –  Eric King Jan 24 '13 at 14:39
1  
3  
"Exceptional" != "Rarely Happens" –  ConditionRacer Jan 24 '13 at 17:30

11 Answers 11

up vote 41 down vote accepted

Exceptions were invented to help make error handling easier with less code clutter. You should use them in cases when they make error handling easier with less code clutter. This "exceptions only for exceptional circumstances" business stems from a time when exception handling was deemed an unacceptable performance hit. That's no longer the case in the vast majority of code, but people still spout the rule without remembering the reason behind it.

Especially in Java, which is maybe the most exception-loving language ever conceived, you shouldn't feel bad about using exceptions when it simplifies your code. In fact, Java's own Integer class doesn't have a means to check if a string is a valid integer without potentially throwing a NumberFormatException.

Also, although you can't rely just on UI validation, keep in mind if your UI is designed properly, such as using a spinner for entering short numerical values, then a non-numerical value making it into the back end truly would be an exceptional condition.

share|improve this answer
5  
Nice swipe, there. Actually, in the real-world app I designed, the performance hit did make a difference, and I had to change it to not throw exceptions for certain parsing operations. –  Robert Harvey Jan 24 '13 at 17:22
10  
I'm not saying there aren't still cases where the performance hit is a valid reason, but those cases are the exception (pun intended) rather than the rule. –  Karl Bielefeldt Jan 24 '13 at 17:38
6  
@RobertHarvey The trick in Java is to throw pre-fabricated exception objects, rather than throw new .... Or, throw custom exceptions, where fillInStackTrace() is overwritten. Then you shouldn't notice any performance degradations, not to speak of hits. –  Ingo Jan 24 '13 at 21:42
3  
+1: Exactly what I was going to answer. Use it when it simplifies the code. Exceptions can give much clearer code where you do not have to bother checking return values on every level in the call-stack. (Like everything else though, if used the wrong way it can make your code a horrible mess.) –  Leo Jan 25 '13 at 7:58
1  
Id say that the fact that exception handling is not as high in overhead is not reason to indugle sloppy code, or to neglect to code for expected values and check for nulls –  Chad Jan 25 '13 at 15:56

When should an exception be thrown? On the high level for some people the answer is clear and for some it is more a philosophical question. For many it is something in between and a question of judgment. However when it comes to code, I think that following explanation for the term exception is very helpful:

An exception is when a member fails to complete the task it is supposed to perform as indicated by its name. (Jeffry Richter, CLR via C#)

Why is it helpful? For me suggests that it depends on the context when something should be handled as an exception or not. On the level of method calls, the context is given by the name and signature of the method AND by the client code, which uses or is expected to use the method.

To answer your question you should have a look on the code, where user input is processed. It might look something like this:

public void Save(PersonData personData) { … }

Does the method name suggest that some validation is done? No. In this case an invalid PersonData should throw an exception.

Suppose that the class has another method which looks like this:

public ValidationResult Validate(PersonData personData) { … }

Does the method name suggest that some validation is done? Yes. In this case an invalid PersonData should not throw an exception.

To put the things together, both methods suggest that the client code should look like this:

ValidationResult validationResult = personRegister.Validate(personData);
if (validationResult.IsValid())
{
    personRegister.Save(personData)
}
else
{
    // Throw an exception? To answer this look at the context!
    // That is: Method name and signature where this code is located
    // and where this method is (expected) to be used.
}

When it is not clear if a method should throw an exception, then maybe it is due a poorly chosen method name or signature. Maybe the design of the class is not clear. By following the resoning above, sometimes you need to modify the design in the code, to get a clear answer to the question if an exception should be thrown or not.

share|improve this answer
    
Just yesterday I made a struct called "ValidationResult" and structured my code the way you describe. –  paul Jan 24 '13 at 13:14
3  
It does not help to answer your question, but I just like to point out that you implicitly or purposely followed the Command-query separation principle (en.wikipedia.org/wiki/Command-query_separation). ;-) –  Theo Lenndorff Jan 24 '13 at 13:21
    
Nice idea! One drawback: In your example, validation is actually performed twice: Once during Validate (returning False if invalid) and once during Save (throwing a specific, well-documented exception if invalid). Of course, the validation result could be cached inside the object, but that would add additional complexity, since the validation result would need to be invalidated on changes. –  Heinzi Oct 21 '13 at 9:27
    
@Heinzi I agree. It could be refactored so that Validate() is called inside the Save() method, and specific details from the ValidationResult could be used to construct an appropriate message for the exception. –  Phil Nov 19 '13 at 13:53
    
Another problem with this approach is that it can only be used if you are sure that there will be no interference from other threads or processes that might affect the validation result. By the time you call Save, the personData may no longer be valid. –  flodin Dec 16 at 10:36

I always think of things like accessing the database server or a web API when thinking of exceptions. You expect the server/web API to work, but in an exceptional case it might not (server is down). A web request might be quick usually, but in exceptional circumstances (high load) it might time out. This is something out of your control.

You users' input data is in your control, since you can check what they send in and do with it what you like. In your case, I'd validate the user input before even trying to save it. And I tend to agree that users providing invalid data should be expected, and your app should account for it by validating the input and providing the user-friendly error message.

That said, I do use exceptions in most of my domain model setters, where there should be absolutely no chance that invalid data goes in. However, this is a last line of defense, and I tend to build my input forms with rich validation rules, so that there's practically no chance of triggering that domain model exception. So when a setter is expecting one thing, and gets another, it is an exceptional situation, which should not have happened in ordinary circumstances.

EDIT (something else to consider):

When sending user provided data to the db, you know beforehand what you should and shouldn't enter into your tables. This means that data can be validated against some expected format. This is something you can control. What you can't control is your server failing in the middle of your query. So you know the query is ok and data is filtered/validated, you try the query and it still fails, this is an exceptional situation.

Similarly with the web requests, you can't know if the request will time out, or fail to connect before you try sending it. So this also warrants a try/catch approach, since you can't ask the server if it will work a few milliseconds later when you send the request.

share|improve this answer
3  
+1, You expect the server/web API to work. –  Qix Jan 24 '13 at 9:13
4  
But why? Why are exceptions less useful in handling problems that are more expected? –  Winston Ewert Jan 24 '13 at 14:59
5  
@Pinetree, checking for file existence before opening a file is bad idea. The file could cease to exist between the check and the open, the file could not have permission that let you open it, and checking for existence and then opening the file will require two expensive system calls. You are better off trying to open the file and then dealing with the failure to do so. –  Winston Ewert Jan 24 '13 at 15:20
7  
As far as I can see, pretty much all possible failures are better handled as recovering from the failure rather then trying to check for success before hand. Whether or not you use exceptions or something else indicate failure is a separate issue. I prefer exceptions because I can't accidentally ignore them. –  Winston Ewert Jan 24 '13 at 15:23
8  
I disagree with your premise that because invalid user data is expected, it can not be considered exceptional. If I write a parser, and someone feeds it unparsable data, that is an exception. I can not continue parsing. How the exception is handled is another question entirely. –  ConditionRacer Jan 24 '13 at 17:40

Exceptions should be exceptional: It's expected that the user may input invalid data, so this isn't an exceptional case

On that argument:

  • It's expected that a file may not exist, so that isn't an exceptional case.
  • It's expected that the connection to the server may be lost, so that isn't an exceptional case
  • It's expected that the configuration file may be garbled so that isn't an exceptional case
  • It's expected that your request may sometimes fall out, so that isn't an exceptional case

Any exception that you catch, you must expect because, well, you decided to catch it. And so by this logic, you should never throw an any exceptions you actually plan to catch.

Hence I think "exceptions should be exceptional" is a terrible rule of thumb.

What you should do depends on the language. Different languages have different conventions about when exceptions should be thrown. Python, for example, throws exceptions for everything and when in Python, I follow suit. C++, on the other hand, throws relatively few exceptions, and there I follow suit. You can treat C++ or Java like Python and throw exceptions for everything, but your working at odds with how the language expects itself to be used.

I prefer Python's approach, but I think it a bad idea to shoehorn other languages into it.

share|improve this answer
    
"Different languages..." - by the way this question is tagged java –  gnat Jan 24 '13 at 15:01
    
@gnat, I know. My point was that you should follow the conventions of the language (in this case Java) even if they aren't your favorite. –  Winston Ewert Jan 24 '13 at 15:18
    
@gnat It's tagged java because I thought the context could be useful, but I am still interested in answers related to other languages. –  Daniel Kaplan Jan 24 '13 at 18:47
3  
+1 "exceptions should be exceptional" is a terrible rule of thumb. Well said! That's one of those things people just repeat without thinking about them. –  Andres F. Jan 24 '13 at 22:51
    
"Expected" is defined by not by subjective argument or convention but by the contract of the API/function (this might be explicit, but is often just implied). Different functions / APIs / subsystems can have different expectations, e.g. for some higher level functionality a non-existing file is an expected case for it to handle (it might report this to a user via a GUI), for other lower level functions it is probably not (and hence should throw an exception). This answer seems to miss that important point.... –  mikera Oct 21 '13 at 6:05

Reference

From The Pragmatic Programmer:

We believe that exceptions should rarely be used as part of a program's normal flow; exceptions should be reserved for unexpected events. Assume that an uncaught exception will terminate your program and ask yourself, "Will this code still run if I remove all the exception handlers?" If the answer is "no," then maybe exceptions are being used in nonexceptional circumstances.

They go on to examine the example of opening a file for reading, and the file doesn't exist - should that raise an exception?

If the file should have been there, then an exception is warranted. [...] On the other hand, if you have no idea whether the file should exist or not, then it doesn't seem exceptional if you can't find it, and an error return is appropriate.

Later, they discuss why they chose this approach:

[A]n exception represents an immediate, nonlocal transfer of control - it's a kind of cascading goto. Programs that use exceptions as part of their normal processing suffer from all the readability and maintainability problems of classic spaghetti code. These programs break encapsulation: routines and their callers are more tightly coupled via exception handling.

Regarding your situation

Your question boils down to "Should validation errors raise exceptions?" The answer is that it depends on where the validation is happening.

If the method in question is within a section of the code where it is assumed that input data has already been validated, invalid input data should raise an exception; if the code is designed such that this method will receive the exact input entered by a user, invalid data is to be expected, and an exception should not be raised.

share|improve this answer

There's a lot of philosophical pontification here, but generally speaking, exceptional conditions are simply those conditions which you cannot or don't want to handle (other than cleanup, error reporting, and the like) without user intervention. In other words, they are unrecoverable conditions.

If you hand a program a file path, with the intention of processing that file in some way, and the file specified by that path doesn't exist, that's an exceptional condition. You cannot do anything about that in your code, other than report it to the user and allow them to specify a different file path.

share|improve this answer
1  
+1, very close to what I was going to say. I would say it is more about scope, and really has nothing to do with the user. A good example of this is the difference between the two .Net functions int.Parse and int.TryParse, the former has no choice but to throw an exception on bad input, the later should never throw an exception –  jmoreno Jan 24 '13 at 16:25
1  
@jmoreno: Ergo, you would use TryParse when the code could do something about the unparseable condition, and Parse when it could not. –  Robert Harvey Jan 24 '13 at 16:26

There are two concerns you should consider:

  1. you discuss a single concern - let's call it Assigner since this concern is to assign inputs to structured objects - and you express the constraint that its inputs be valid

  2. a well-implemented user-interface has an additional concern: validation of user input & constructive feedback on errors (let's call this part Validator)

From the point of view of the Assigner component, throwing an exception is totally reasonable, since you've expressed a constraint that has been violated.

From the point of view of the user experience, the user shouldn't be talking directly to this Assigner in the first place. They should be talking to it via the Validator.

Now, in the Validator, invalid user input is not an exceptional case, it's really the case you're more interested in. So here an exception wouldn't be appropriate, and this is also where you'd want to identify all errors rather than bailing out on the first.

You'll notice I didn't mention how these concerns are implemented. It seems you're talking about the Assigner and your colleague is talking about a combined Validator+Assigner. Once you realise there are two separate (or separable) concerns, at least you can discuss it sensibly.


To address Renan's comment, I'm just assuming that once you've identified your two separate concerns, it's obvious what cases should be considered exceptional in each context.

In fact, if it isn't obvious whether something should be considered exceptional, I'd argue you probably haven't finished identifying the independent concerns in your solution.

I guess that makes the direct answer to

... how do I know if my case is exceptional?

keep simplifying until it is obvious. When you have a pile of simple concepts you understand well, you can reason clearly about composing them back into code, classes, libraries or whatever.

share|improve this answer
    
-1 Yep, there are two concerns, but this does not answer the question "How do I know if my case is exceptional?" –  RMalke Jan 24 '13 at 11:45
    
The point is the same case can be exceptional in one context, and not in another. Identifying which context you're actually talking about (rather than conflating them both) answers the question here. –  Useless Jan 24 '13 at 11:47
    
... actually, maybe it doesn't - I've addressed your point in my answer, instead. –  Useless Jan 24 '13 at 11:56

Others have answered well, but still here is my short answer. Exception is situation where something in the environment has wrong, which you can not control and your code can not go forward at all. In this case you will also have to inform the user what went wrong, why you cannot go further, and what is the resolution.

share|improve this answer

Exceptions should represent conditions that it's likely the immediate calling code will not be prepared to handle, even if the calling method might. Consider, for example, code which is reading some data from a file, may legitimately assume that any valid file will end with a valid record, and is not required to extract any information from a partial record.

If the read-data routine didn't use exceptions but simply reported whether or not the read succeeded, the calling code would have to look like:

temp = dataSource.readInteger();
if (temp == null) return null;
field1 = (int)temp;
temp = dataSource.readInteger();
if (temp == null) return null;
field2 = (int)temp;
temp = dataSource.readString();
if (temp == null) return null;
field3 = temp;

etc. spending three lines of code for each useful piece of work. By contrast, if readInteger will throws an exception upon encountering the end of a file, and if the caller can simply pass on the exception, then the code becomes:

field1 = dataSource.readInteger();
field2 = dataSource.readInteger();
field3 = dataSource.readString();

Much simpler and cleaner looking, with far greater emphasis on the case where things work normally. Note that in cases where the immediate caller would be expecting to handle a condition, a method which returns an error code will often be more helpful than one which throws an exception. For example, to total all the integers in a file:

do
{
  temp = dataSource.tryReadInteger();
  if (temp == null) break;
  total += (int)temp;
} while(true);

versus

try
{
  do
  {
    total += (int)dataSource.readInteger();
  }
  while(true);
}
catch endOfDataSourceException ex
{ // Don't do anything, since this is an expected condition (eventually)
}

The code which asking for the integers is expecting that one of those calls is going to fail. Having the code use an endless loop which will run until that happens is far less elegant than using a method that indicates failures via its return value.

Because classes often won't know what conditions their clients will or will not expect, it's often helpful to offer two versions of methods that could fail in ways that some callers will expect and other callers won't. Doing so will allow such methods to be used cleanly with both types of callers. Note also that even "try" methods should throw exceptions if situations arise the caller probably isn't expecting. For example, tryReadInteger should not throw an exception if it encounters a clean end-of-file condition (if the caller weren't expecting that, the caller would have used readInteger). On the other hand, it probably should throw an exception if the data could not be read because e.g. the memory stick containing it was unplugged. While such events should always be recognized as a possibility, it's unlikely that the immediate calling code would be prepared to do anything useful in response; it should certainly not be reported the same way as would be an end-of-file condition.

share|improve this answer

The most important thing in writing software is making it readable. All other considerations are secondary, including making it efficient and making it correct. If it's readable, the rest can be taken care of in maintenance, and if it's not readable then you're better off just throwing it away. Therefore, you should throw exceptions when it enhances readability.

When you're writing some algorithm, just think about the person in the future who will be reading it. When you come to a place where there could be a potential problem, ask yourself if the reader wants to see how you handle that problem now, or would the reader prefer to just get on with the algorithm?

I like to think of a recipe for chocolate cake. When it tells you to add the eggs, it has a choice: it can either assume you have eggs and get on with the recipe, or it can begin an explanation for how you can get eggs if you don't have eggs. It could fill a whole book with techniques for hunting wild chickens, all to help you bake a cake. That's good, but most people aren't going to want to read that recipe. Most people would prefer to just assume that eggs are available, and get on with the recipe. That's a judgement call that authors need to make when writing recipes.

There can't be any guaranteed rules about what makes a good exception and what problems should be handled immediately, because it requires you to read the mind of your reader. The best you'll ever do is rules of thumb, and "exceptions are only for exceptional circumstances" is a pretty good one. Usually when a reader is reading your method they are looking for what the method will do 99% of the time, and they'd rather not have that cluttered with bizarre corner cases like dealing users entering illegal input and other stuff that almost never happens. They want to see the normal flow of your software laid out directly, one instruction after another as if problems never happen. Understanding your program is going to be hard enough without having to deal with constantly going off on tangents to deal with every little problem that might come up.

share|improve this answer

I've never been a great fan of the advice that you should only throw exceptions in cases that are exceptional, partly because it doesn't say anything (it's like saying that you should only eat food that is edible), but also because it is very subjective, and it's often not clear what constitutes an exceptional case and what doesn't.

However, there are good reasons for this advice: throwing and catching exceptions is slow, and if you are running your code in the debugger in Visual Studio with it set to notify you whenever an exception is thrown, you can end up being spammed by dozens if not hundreds of messages long before you get to the problem.

So as a general rule, if:

  • your code is bug free, and
  • the services on which it depends are all available, and
  • your user is using your program in the way that it was intended to be used (even if some of the input they provide is invalid)

then your code should never throw an exception, even one that is caught later. To trap invalid data, you can use validators at the UI level or code such as Int32.TryParse() in the presentation layer.

For anything else, you should stick to the principle that an exception means that your method can not do what its name says that it does. In general it's not a good idea to use return codes to indicate failure (unless your method name clearly indicates that it does so, e.g. TryParse()) for two reasons. First, the default response to an error code is to ignore the error condition and carry on regardless; second, you can all too easily end up with some methods using return codes and other methods using exceptions, and forgetting which is which. I have even seen codebases where two different interchangeable implementations of the same interface take different approaches here.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.