When validating data, I\'ve gotten into a habit of doing the following:
Note: I don\'t really have individual booleans for each check. This is just
I support MusiGenesis's answer.
Additionally...
The performance of throwing an exception is a thousand instructions. It's nothing compared to end-user time, but in inner code it is slow.
An additional problem is that, using Exceptions, your validation is limited to reporting the first failure (and you will have to do it all again next time to find the next failure).
So maybe in some languages exception throwing and catching is "costly" but in other languages, throwing and catching exceptions is exactly what's called for.
In Smalltalk, for example, one could quickly build a multi-tiered exception catching solution. The validation pass could collect up any number of exceptions representing EVERYTHING that's wrong with a particular input data set. Then it would throw them ALL up to a higher-level catcher, responsible for formatting up a human-readable explanation of, again, EVERYTHING that was wrong with the input. In turn it would throw a single exception further up the chain, along with that formatted explanation.
So... I guess what I'm saying is, exceptions are only bad to throw if you've got no exception handling architecture supporting catching them and doing reasonable things with them, and all your catcher is going to do is EXIT or do something else equally inappropriate.
This is bad behavior. Exceptions are for Exceptional conditions. They take resources to generate the stack etc. Exceptions should not be used to dictate process flow.
I would suggest that using exceptions as described in the question (for flow control within a function) is wrong not usually the best idea. I'd go further and saying validation throwing exceptions isn't the best approach; instead return a Boolean and store a list of validation error messages that can be accessed. An accompanying save method could/should throw an exception if it is called on an invalid object.
Thus if validate fails validation error messages can be displayed to the user (logged, returned. whatever). If validation passes then you can call save. If you call save on an invalid object then get get an appropriate exception.
Another potential problem with your example code (depending on requirements of course) is it only throws the first validation error that occurs. Imagine this from a users POV:
As a user I'd prefer to get all validation errors returned at once so I can correct them all before trying again.
Personally I like throwing Exceptions for business rule validation (not so much for user input validation) because it forces the problem to be handled upstream. If my business objects returned some kind of validation result, it could be ignored by the caller. Call me a cowboy if you wish :)
Everyone here is repeating the phrase "exceptions are for exceptional circumstances", but that really doesn't give any understanding of why its bad to use them for unexceptional circumstances. I need more than that. Is the performance hit of throwing exceptions really that bad? Are there any benchmarks available?
Well, i know it's an old question. But i'll let my opinion here for the googler's who falled here like me:
An example:
/*
* Here it's a common problem i have: Someone pass a list of products i need to
* retrieve from the database and update some information;
*/
//This is a class to represent the product
function Product(id, name, price) {
this.id = id;
this.name = name;
this.price = price;
}
//This is an example function to retrieve the product from the database
function findProductInDatabase(productId) {
//If the product exists on the database, the function will return it
if (productId == 12) {
var product = new Product(12, "Book", 20.5);
return product;
}
//If the product do not exists, it will return null
return null;
}
//This is a function that will receive the productID and will update the received parameters
function updateProduct(productId, newProductName, newProductPrice) {
var productFromDatabase = null;
var errorMessage = "";
//Retrieve the product
productFromDatabase = findProductInDatabase(productId);
//If the product do not exist, i need to interrupt de method imediatily and alert the caller
if (!productFromDatabase) {
throw "Product not found";
}
//Validate the other parameters, but in this case i can validate all the parameters
if (newProductPrice < 10) {
errorMessage += "the price is too low";
}
if (newProductName.includes("<")) {
//If already has a error message in the variable i append " and " to the message make sense
if (errorMessage) {
errorMessage += " and ";
}
errorMessage += "the new name has invalid characters";
}
if (errorMessage) {
//if theres any error, i will throw a exception with the messages
throw errorMessage;
}
}
//This parte is where the method id called;
try {
updateProduct(9, "Book", 10.5);
} catch (exception) {
console.log("Case 1: " + exception);
}
try {
updateProduct(12, "<Book", 9);
} catch (exception) {
console.log("Case 2: " + exception);
}