Is it a good or bad idea throwing Exceptions when validating data?

Viewed 36872

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 for the example.

Another Note: any error handling during the tests are done properly. The ONLY exceptions thrown in the try-catch are my own.

try {
  if (validCheckOne = false) {
    throw new Exception("Check one is bad");
  }
  if (validCheckTwo = false) {
    throw new Exception("Failed because of check2");
  }
  if(validCheckTen = false) {
    throw new Exception("Yet another failure on your part: check10.");
  }
} catch(Exception e) {
  MessageBox.Show("Your stupid data is wrong! See for yourself: " + e.Message);
}

Is this bad practice? Does throwing Exceptions slow the program's execution or is inadvisable?

17 Answers

When you go to the grocery and ask the seller if he's got cheese, and the seller replies with no, would that be an unexpected or exceptional response? What about if you do the same but the seller just looks at you and does not respond!

Another example, you are talking to your friend and ask if there is something wrong, you may get 2 responses:

  • They tell you that they are sad because of something.
  • Or they just look at you and say nothing, turn their back and walk away and you are sure that this means you're in deep trouble :)

Same way with exceptions, unexpected behavior is an exception, but an invalid but expected response should not - IMHO - throw exceptions.

This question is still interesting, mainly because of the answers.

When it comes to exception, there is a lot of arguments involved. We can defend a point to any direction we want to, from performance to exception philosophy. And they all sounds right to me.

But sometimes we have to stick to a direction. In this case, I think it's the validation itself.

When we want to validate something we also want to know (to log, or to show the user) whats wrong when the parameter is invalid. Even thought there are layers of validation such as Business Validation mixed with User Input validations.

For instance, when dealing with user input, a lot of weird cases can happen. A pasted data from a website full of hidden char (\t \n etc), typos, and a really huge kinds of cases that a specific exception could allow further analysis or message to the uses much more precisely than a simple "false" return.

Well, i know it's an old question. But i'll let my opinion here for the googler's who falled here like me:

  1. If you are using a language with a bad try/catch support AVOID THROWING exceptions for data validation;
  2. DO NOT THROW a exception that will not be handled by the caller or alserwhere;
  3. DO NOT THROW a exception if you need to validate the rest of the received data;
  4. You can THROW a exception in cases where the code block cannot continue without the invalid data; And if you do not interrupt the process you can get a unhandled exception;

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);
}

I often write similar code for validation, especially in express.js, and similar request/response loop style applications. When something is invalid, I throw a ValidationError, it's caught by the top level error handler, which knows to send a 422 response with the additional information that's attached to the ValidationError.

It's a very convenient way to handle validation. You don't have to pass around an error object (potentially up through a dozen stack frames, in some cases). And it's a simple and consistent way to trigger an invalid input response. I haven't experienced any serious problems with this approach.

I've thought about the "don't use exceptions for flow control" maxim in relation to this practice, and decided the benefits outweigh any disadvantages. I would say if you understand the reasoning behind "don't use exceptions for flow control", but you determine that it's a good idea anyway in a certain case, then go ahead and do it. We don't need to be too dogmatic about these things.

Throwing exceptions is relatively slow, but that will only matter if you're doing it repeatedly in a loop.

In test, sure, but in a live environment, you'd hope they're never raised. You'd hope to refactor your code to the extent that all data into your system are validated at source, and either the user, or the system that generated the input to your system, is notified of the issue. Exceptions should occur if you've missed something and should be a fallback that is handled gracefully. You could store anything that's causing these exceptions separately, so that they don't make it into your system without being checked over first. You don't want, e.g. an invalid value that falls outside a range of values to skew your results.

Related