I'm trying to both learn more about the implications of various design choices, and find the most performant solution for preventing errors in my code. Before diving in, allow me to briefly and generally state my question:
Is a try catch block a more efficient solution to handling an out of bounds exception when compared to and if-statement structure?
I understand that raising exceptions is expensive, but is that cost mitigated by removing unnecessary if-statements?
And now, allow me to state my specific issue to give you more useful information.
I'm building a game, and part of that game is a world-grid solution coupled with a pathfinder. Game Units may request nodes from the world-grid, (by sending coordinate information as an ordered pair (x, z)), to then send to the pathfinder or perform on them some other miscellaneous action. Because nodes are being requested with a large amount of frequency, especially by the pathfinder, this seems like a smart place to try to optimize.
Here is my current code for returning a given node based on its x and z values in the array of nodes:
public Node GetTile(int x, int z)
{
if (x < 0)
x = 0;
if (x >= length_X)
x = length_X - 1;
if (z < 0)
z = 0;
if (z >= length_Z)
z = length_Z - 1;
return tiles [x, z];
}
As you can plainly see, I have several if statements in place to avoid out of bounds exceptions when retrieving a node from world-grid's array of nodes(tiles). Is this the most efficient solution? Could I remove the if's and instead place the return in a try catch block like so:
public Node GetTile(int x, int z)
{
try
{
return tiles[x, z];
}
catch (System.IndexOutOfRangeException e)
{
//handle exception here
//do smart programming fix-y stuff
}
}
This solution works, but is there some reason that I'm not aware of that makes it less efficient? My logic for believing it to be a smarter solution is that I'm removing up to four comparisons every single time the method is called. Considering the circumstances under which the program will actually send in values out side of the bounds are rare, this seems like a good trade off. What I don't know though, is how exceptions work behind the scenes. Will checking for an exception be just as expensive as checking the values manually?
UPDATE:
After reading through the replies here I now have a better understanding of the topic in general. I've run some tests on my code accounting for various cases running 10 million iterations.
In line with my general hypothesis, if we assume that there will never be a case where input results in an exception, then the try catch block is indeed faster. However, in the case where approximately 10% the calls to the method raise an exception, the performance is over 5 times slower. I tested various percentages and it seems that the threshold for better performance in my case is near 1%.
As of yet, I'm not sure what percentage of calls will indeed actually raise an exception, but I believe that the number will be much much lower than 1%. Therefore, I can safely, unless further testing shows otherwise, use the try-catch block to ensure my code runs without fatal errors.
Thanks to everyone who contributed.
Exceptions are not made to control the flow of your code. They are made to treat "exceptional" circumstances, e.g. connection issues or invalid file formats.
If you want to control your code flow, you should use conditional statements like if
, else
and switch
.
The performance of exceptions is generally bad compared to some simple if
-statement, but there are also situations where exception-handling might be faster than checking data for validity manually.
There might also be plenty of situations where you know an exception could be raised, but you simply trust the data - e.g. checking your own settings file for valid xml format. Data validation is paid in CPU-time.
Most of the time you want to use Exceptions
in order to have error information later, e.g. line number of the error in the xml file and to recover your application in some way (e.g. reconnect to a socket).
You can not give a general statement about the performance of exceptions, but when you can avoid them, you should.
A small example where you can potentially avoid exceptions:
try
{
LoginUser("Fooooo", "Bar");
} catch(InvalidCredentialsException e) {
// handle
}
private static void LoginUser(string pUsername, string pPassword)
{
if (pUsername != "Foo" || pPassword != "Bar")
throw new InvalidCredentialsException("Invalid username and/or password");
GrantAccess(pUsername);
}
Instead of throwing the exception you could also just return a boolean:
if (!LoginUser("Fooooo", "Bar"))
{
// handle
}
private static bool LoginUser(string pUsername, string pPassword)
{
if (pUsername != "Foo" || pPassword != "Bar")
return false;
GrantAccess(pUsername);
return true;
}
Performance on my machine running 10000 attempts with invalid credentials:
throwing Exception
: 181990454 ticks
returning boolean
: 644 ticks
I guess you can see and especially feel the difference.