if(condition) {the two blocks of code, A and B, can easily be reversed by negating the condition like this
… A …
}
else {
… B …
}
if(!condition) { // notice the '!'So, which is preferable? if-A-else-B or if-B-else-A? The answer I hear the most is: "Well... that just depends on the if condition." Unfortunately, that is not the correct answer – Far from it.
… B …
}
else {
… A …
}
Identify the normal flow
In the statement above, the condition helps us distinguish between two different situation – one situation where the condition holds, and one where it does not. Quite often, the condition is relatively easy to write, e.g.
if(list.size() == 0) {…}
so many developers just write what ever plausible condition that comes to mind, and use the condition to decide which code to put in the A and B blocks respectively. So let us say, that it is illegal for the list to be empty, the code might end up like this
Think for a second, how you would be able to understand the purpose of a code segment if you where presented with several catch blocks first.
if(list.size() == 0) {While this may be logically correct, the problem here is the code ordering. The rare case, where someone invoked this code with an empty list, now comes first, while the normal flow, comes last. That is wrong, for several reasons.
throw new AnEmptyListIsNotAllowedException();
}
else {
// do something useful
…
}
Think: Try-then-catch
When Java was designed back in the mid 90s, the designers chose to adopt the famed C++ exception facility where you could concentrate on the normal flow of you code, and then leave the rare, exceptional cases to their own appended code blocks, as intry {One of the advantages of this design was the fact, that both the code author, and any other developer who might later need to maintain the code, could now start out by reading and understanding the important part of the code: The normal flow. Once you have understood this normal flow, you know what the purpose of the whole code segment is; consequently, it gets much easier to understand the exception handling in the following catch blocks.
// do something useful
…
}
catch(AnException exception) {
// handle the exception
…
}
Think for a second, how you would be able to understand the purpose of a code segment if you where presented with several catch blocks first.
Reversing the condition
Obviously, the if-else example presented earlier is simple to fix, by just reversing the condition:
if(list.size() > 0) {// do something useful
…
}
else {
throw new AnEmptyListIsNotAllowedException();
}
If you start practicing this, you will notice that in more complex scenarios (if-else-else-else), this really is helpful in making your code readable. And in 12 months from now when you get back to the code to maintain it, understanding what is going on will be so much easier.