Java: Exceptions as a control flow?

I heard that using exceptions for control flow is bad practice. What do you think about it?

public static findStringMatch(g0, g1) { int g0Left = -1; int g0Right = -1; int g1Left = -1; int g1Right = -1; //if a match is found, set the above ints to the proper indices //... //if not, the ints remain -1 try { String gL0 = g0.substring(0, g0Left); String gL1 = g1.substring(0, g1Left); String g0match = g0.substring(g0Left, g0Right); String g1match = g1.substring(g1Left, g1Right); String gR0 = g0.substring(g0Right); String gR1 = g1.substring(g1Right); return new StringMatch(gL0, gR0, g0match, g1match, gL1, gR1); } catch (StringIndexOutOfBoundsException e) { return new StringMatch(); //no match found } 

So, if no match is found, int will be -1. This will throw an exception when I try to take the substring g0.substring(0, -1) . Then the function simply returns an object indicating that no match was found.

Is this a bad practice? I could just check each index manually to see if they are all -1, but that seems to work.

UPDATE

I removed the try-catch block and replaced it with this:

  if (g0Left == -1 || g0Right == -1 || g1Left == -1 || g1Right == -1) { return new StringMatch(); } 

Which is better: checking if each variable is -1, or using the boolean foundMatch to track and just check what at the end?

+7
java exception control-flow
Oct 09 '09 at 23:27
source share
4 answers

Typically, exceptions are expensive operations and, as the name implies, exceptional conditions. Thus, using them in the context of controlling the flow of your application is indeed considered bad practice.

In particular, in the example you provided, you need to do some basic validation of the input data that you provide to the StringMatch constructor. If it were a method that returns an error code in case of a failure to validate the base parameter, you can avoid the check in advance, but it is not.

+15
Oct 09 '09 at 23:30
source share

I did some tests on this. On modern JVMs, this does not actually affect runtime performance (if at all). If you start with debugging enabled, this will significantly slow down the process.

For more details see below.

(I should also mention that I still think that this is bad practice, even if it does not affect performance. Moreover, it reflects perhaps a poor design of the algorithm, which will be difficult to verify)

+7
Oct 10 '09 at 0:13
source share

Yes, this is bad practice, especially when you have a way to avoid an exception (check the length of the string before trying to index it). The try and catch blocks are designed to separate the "normal" logic into an "exceptional" and a logical error. In your example, you propagated the β€œnormal” logic to an exceptional / error block (not finding a match is not exceptional). You are also abusing substring so you can use the error it produces as a control flow.

+5
Oct 10 '09 at 0:10
source share

The program flow should be as direct as possible (since even then applications become quite complex) and use standard control flow structures. The next developer, who might touch the code, may not be you and (correctly) misunderstand the non-standard way of using exceptions instead of conditional expressions to define the control flow.

I am struggling with a slightly different bias from this problem right now while refactoring old code.

The biggest problem I find with this approach is that using try / catch interrupts the normal program flow.

In the application I'm working on (and this is different from the sample that you used), exceptions are used to communicate from a method call that gives the given result (for example, it searches for the account number and does not find it) happened. This creates client-side spaghetti code because the calling method (during a non-exceptional event or case of a normal use case) breaks out of any code that it executed before the call and into the catch block. This is repeated in some very long methods many times, which makes the code very easy to read incorrectly.

In my situation, the method should return a value for each signature for all but truly exceptional events. The exception handling mechanism is designed to take a different path when an exception occurs (try and restore it inside the method so that you can return normally).

In my opinion, you could do this if you very much endowed your try / catch blocks; but I think this is a bad habit and can lead to code that is very easy to misinterpret, as the calling code interprets any abandoned exception as a message like "GOTO" , changing the program flow. I am afraid that although this case does not fall into this trap, it can often lead to a coding habit leading to the nightmare that I live now.

And I do not like this nightmare.

+5
Feb 19 '10 at 18:14
source share



All Articles