This is purely a design question and the example is simple to illustrate what I am asking and there are too many permutations of more complex code to provide examples that would cover the topic. I am not referring specifically to this example, just using the example to illustrate what I am referring to.
In an if statement, is there a preferred way to order conditions, in terms of coding convention and, more importantly, efficiency?
For such a simple example, efficiency will not be an issue, but I am not asking for a code review per se, but an understanding of the concept.
Two alternatives:
1.
public double myStuff(int i)
{
// check for an invalid number of tourists
if (i > 0)
{
// do something here
return doubleSomething;
} else
{
return Double.NaN;
}
}
2.
public double myStuff(int i)
{
if (i <= 0)
{
return Double.NaN;
} else
{
{
// do something here
return doubleSomething;
}
If the if statement was to become more complex, and possibly nested, in what order should conditions be addressed?
10
When it comes to large if
blocks, optimization isn’t really an issue. The compiler will generate pretty much the same result no matter how you organize them, assuming that the conditions are equally easy to calculate.
One technique I like to use is to use “guard statements” to check for invalid input right away, at the top of the method body. This way, the rest of the method can be formatted with the assumption that the arguments are already valid.
public double myStuff(int i, SomeOtherArgument widget) {
// Perform any simple checks for invalid data right away and
// fail fast if something smells bad.
if (i <= 0)
return Double.NaN;
if (widget == null)
throw new IllegalArgumentException();
// If the stuff you've done above this line is trivial, there's no reason
// to wrap the rest of the method body in a big else block. It's just noise.
return doABunchOfWork();
}
5
Efficiency is not usually a real concern for structuring if-statements, even if they are complex or nested. There are ways to nest if-statements that could be less efficient than others, but if the code is only run once and takes 5 nanoseconds too long, you aren’t even going to be able to notice that there’s a difference.
It is possible for this sort of thing to make a real difference in the running time of a program, especially if it’s in the innermost loop of some nested loops. However, the best way to deal with a slow program is to measure it and find out where it’s spending most of its time, so you can make that spot more efficient — whether or not that spot has anything to do with nested if-statements.
What should be the concern for if-statements (especially nested or complex ones) is readability. It is very easy to make an unreadable mess out of complex nested if-statements, and the harder code is to read, the harder it is to ensure that it’s correct or to debug it.
For simple if-statements, try to keep the condition from being too crazy. If you can’t avoid a complex condition, try using formatting to clarify it, or use a helper function to evaluate the condition.
Mess:
if(a <= 5 && b > 10 && c < 4 && b <= 100
&& a > 2 && c > 1)
Better formatting:
if( (a > 2) && (a <= 5) &&
(b > 10) && (b <= 100) &&
(c > 1) && (c < 4) )
Helper function:
if( withinLimits(a, b, c) )
Also, try to avoid double-negatives. “I wouldn’t say that’s not an incorrect statement” is hard to read. “That’s wrong” is easy to read, and means the same thing. Single negatives aren’t so bad, but sometimes you can make things a bit clearer by stating something positively instead.
For nested if-statements, it depends on how they’re nested.
For something like this:
if(a) {
if(b) {
if(c) {
something;
}
}
}
You could replace it with something like this:
if(a && b && c) {
something;
}
If you have a complex nesting of if-statements, it’s probably a mess. How to clean it up exactly depends on what exactly it is. It may be possible to create a decision table — an array that has indices that represent what we’re basing the decision on and entries that are the resulting decision. If so, we can just look up the answer without using any if-statements at all.
For composite conditions, you could consider to take into account the fact that, in Java, conditions evaluation is lazy. That means that the program will only evaluate the (sub)conditions until it can decide if the conditional statements must be executed or not.
So, for instance, if you have two conditions c1 and c2, and if c1 can be quickly evaluated since c2 take a while to be evaluated, prefer if(c1 and/or c2)
to if(c2 and/or c1)
, so that you could more quickly determine if the global condition is respected or not. Similarly, prefer
if(c1){
if(c2){
(...)
}
}
to
if(c2){
if(c1){
(...)
}
}
In the worse case it does not change anything, and in the best case you spare a test.
This is a general principle, you can also consider the fact that one of the conditions will be true virtually all the times. In that case, it could be interesting to place it first in a OR composition, so that you will virtually never test the second condition. It becomes harder to decide how to order the conditions when you have to consider simultaneously time consumption and value probability.
Be aware that before changing the order of your conditions, you must be sure they imply no side effect, otherwise a reordering may change the behaviour of your program.
2