Why are Exceptions said to be so bad for Input Validation?

I understand that "Exceptions are for exceptional cases" [a], but besides just being repeated over and over again, I've never found an actual reason for this fact.

Being that they halt execution, it makes sense that you wouldn't want them for plain conditional logic, but why not input validation?

Say you were to loop through a group of inputs and catch each exception to group them together for user notification... I continually see that this is somehow "wrong" because users enter incorrect input all the time, but that point seems to be based on semantics.

The input is Not what was expected and hence is exceptional. Throwing an exception allows me to define exactly what was wrong like StringValueTooLong or or IntegerValueTooLow or InvalidDateValue or whatever. Why is this considered wrong?

Alternatives to throwing an exception would be to either return (and eventually collect) an error code or far worse an error string. Then I would either show those error strings directly, or parse the error codes and then show corresponding error messages to the user. Wouldn't a exception be considered a malleable error code? Why create a separate table of error codes and messages, when these could be generalized with the exception functionality already built into my language?

Also, I found this article by Martin Fowler as to how to handle such things - the Notification pattern. I'm not sure how I see this as being anything other than Exceptions that don't halt execution.

a: Everywhere I've read anything about Exceptions.

--- Edit ---

Many great points have been made. I've commented on most and +'d the good points, but I'm not yet completely convinced.

I don't mean to advocate Exceptions as the proper means to resolve Input Validation, but I would like to find good reasons why the practice is considered so evil when it seems most alternate solutions are just Exceptions in disguise.


Solution 1:

Reading these answers, I find it very unhelpful to say, "Exceptions should only be used for exceptional conditions". This begs the whole question of what is an "exceptional condition". This is a subjective term, the best definition of which is "any condition that your normal logic flow doesn't deal with". In other words, an exceptional condition is any condition you deal with using exceptions.

I'm fine with that as a definition, I don't know that we'll get any closer than that anyway. But you should know that that's the definition you are using.

If you are going to argue against exceptions in a certain case, you have to explain how to divide the universe of conditions into "exceptional" and "non-exceptional".

In some ways, it's similar to answering the question, "where are the boundaries between procedures?" The answer is, "Wherever you put the begin and end", and then we can talk about rules of thumb and different styles for determining where to put them. There are no hard and fast rules.

Solution 2:

A user entering 'bad' input is not an exception: it's to be expected.

Exceptions should not be used for normal control flow.

In the past many authors have said that Exceptions are inherently expensive. Jon Skeet has blogged contrary to this (and mentioned a few time in answers here on SO), saying that they are not as expensive as reported (although I wouldn’t advocate using them in a tight loop!)

The biggest reason to use them is ‘statement of intent’ i.e. if you see an exception handling block you immediately see the exceptional cases which are dealt with outside of normal flow.

Solution 3:

There is one important other reason than the ones mentioned already:

If you use exceptions only for exceptional cases you can run in your debugger with the debugger setting "stop when exception is thrown". This is extremely convenient because you drop into the debugger on the exact line that is causing the problem. Using this feature saves you a fair amount of time every day.

In C# this is possible (and I recommend it wholeheartedly), especially after they added the TryParse methods to all the number classes. In general, none of the standard libraries require or use "bad" exception handling. When I approach a C# codebase that has not been written to this standard, I always end up converting it to exception-free-for-regular cases, because the stop-om-throw is so valuable.

In the firebug javascript debugger you can also do this, provided that your libraries don't use exceptions badly.

When I program Java, this is not really possible because so many things uses exceptions for non-exceptional cases, including a lot of the standard java libraries. So this time-saving feature is not really available for use in java. I believe this is due to checked exceptions, but I won't start ranting about how they are evil.