- Exceptions in Java
- Using Exceptions To Write Elegant Code
- The Problem: Using Exceptions for Control-Flow
- Performance Tests of the Two Code Samples
- Summary
The Problem: Using Exceptions for Control-Flow
In some programming situations, it's easy to use exceptions as a way of controlling the normal execution. In such cases, an exception is not used as an unexpected error condition, but rather in place of a conditional or counted termination of a regular loop, or to handle the rare (but not erroneous) case of a conditional statement. In such cases, the exception is handled and execution continues in a planned manner. Most of the time, these exceptions can be avoided by rewriting code to have explicit checksthough sometimes at the cost of some readability.
One situation that lends itself more easily to this type of coding is when converting a finite-state machine algorithm to a program. Usually there's a lot of string processing that uses buffers of sizes that may not match up. Instead of introducing a check at every point, it would be easier to simply code everythingusing exceptions to refill buffers and using global variables as indices. The result would be similar to the method shown in Listing 4.
Listing 4
static int countCharsWithExcep() { char[] locBuffer = new char[5]; int locIdx = 0; int numExp = 0; while (globCounter++ < maxIter) { while(true) { try { locBuffer[locIdx] = globalBuffer[globIdx++]; updateCounter(locBuffer[locIdx++]); } catch (ArrayIndexOutOfBoundsException ex) { ++ numExp; if (locIdx >= locBuffer.length) { locIdx = 0; --globIdx; continue; } else break; } } globIdx = 0; } return numExp; }
Instead of explicitly checking for array indices being out of bounds, this is handled in the exception-handling code, and execution continues after resetting the indices. While the example is a small part of a larger program that uses this philosophy in a more complex way, it still serves to prove the point about Java performance.
We might rely on good exception-handling performance from the underlying Java virtual machine (JVM) and avoid using conditionals, believing that would impair the performance of the common case. But most JVMs handle exceptions as rare and unexpected events. The JVM has to potentially unwind the call stack all the way to the top calling method to hunt for a handler for the exception. Even if a handler is available in the current method itself, some JVMs may still jump from native generated code to handle the exception code in the runtime system. Such JVM mechanisms to handle exceptions can provide acceptable performance so long as exceptions are rare; the simplicity of this implementation can take precedence over improving the performance of a rare condition (which, moreover, could end in termination of the program). If the programmer uses an exception more commonly, a particular method can become a major bottleneck.
We can modify the countChars code in Listing 4 to use conditionals instead of exceptions, as shown in Listing 5.
Listing 5
static void countCharsNoExcep() { char[] locBuffer = new char[5]; int locIdx = 0; while (globCounter++ < maxIter) { while(true) { if (locIdx >= locBuffer.length) { locIdx = 0; } if (globIdx >= globalBuffer.length) break; locBuffer[locIdx] = globalBuffer[globIdx++]; updateCounter(locBuffer[locIdx++]); } globIdx = 0; } }