If Then (If Then Else) Else (If Then Else)


In the same series than Andy Maleh post to-if-else-or-not-to-if-else and after discussions with colleagues I am wondering how you write the following problem using Java If-Else.

Object a;
Object b;
a == null and b == null -> method1()
a == null and b != null -> method2()
a != null and b != null -> method3()
a != null and b == null -> method4()

Which method to choose taking into account performances and redability between:

if (a == null && b == null) {
method1();
} else if (a == null && b != null) {
method2();
} else if (a != null && b != null) {
method3();
} else {
method4();
}

Or

if (a == null) {
if (b == null) {
method1();
} else {
method2();
}
} else {
if (b != null) {
method3();
} else {
method4();
}
}

About readability I’ll personally choose the first solution. About performances … I am not sure there is a difference after JVm’s optimizations … ??

Advertisements

17 thoughts on “If Then (If Then Else) Else (If Then Else)

  1. I suppose that if you didn’t care about performance at all, you might not even use an else but rather insist on a completely bogus fourth condition because it’s more readable and explicit. Carried to the extreme, you might include a fifth else with the assertion that you can’t get here ever. Personally I don’t think I could stand the thought of having extra conditions being tested just because someone “else” argued it was more readable that way. Imagine if the conditions involved method calls or something “else” significantly expensive. Would the answer be the same, or would you have to introduce boolean variables to store the intermediate results of the condition test so that the boolean variables could be repeated without obvious gross overhead?

  2. I’d do it like this:

    int selector = 0;

    if (a != null) selector += 1;
    if (b != null) selector += 2;

    switch(selector){
    case 0 : method1(); break;
    case 1 : method4(); break;
    case 2 : method2(); break;
    case 3 : method3(); break;
    }

    This method scales better. Say you have a third object. Just do:

    if (c != null) selector += 4; // Always use a power of 2

    Also, it’s easy to map more than one condition to the same method invocation. Say:

    case 4:
    case 6: method5(); break;
    case 5: method6(); break;

  3. Thanks to all for your answers.

    > #2 would be much readable if the brackets were indented correctly.
    Of course !!

    > I’d do it like this:
    > int selector = 0; …

    I agree with you about scalability. I’ll use this solution for that purpose. About readability I think this one is the hardest to understand

    > Personally I don’t think I could stand the thought of having extra conditions
    Even in pieces of code that do not care at all about performances ?? Personally I already do that in such places.

    Manu

  4. > I agree with you about scalability. I’ll use this solution for that purpose. About readability I think this one is the hardest to understand

    How about using bit constants for this, instead of magic numbers?

    int valid = NONE

    if (a != null) selector += A_VALID;
    if (b != null) selector += B_VALID;

    switch(selector){
    case NONE : method1(); break;
    case A_VALID : method4(); break;
    case B_VALID : method2(); break;
    case A_VALID|B_VALID : method3(); break;
    }

    This approach is not without it’s own problems (when you try to scale, it’s easy to miss a particular combination), but I think it’s OK if you only have 2 or 3 variables to check.

  5. (I should read what I post more carefully, the variable names don’t match, selector and valid is the same var… but I hope the point is clear)

  6. Using bits results in less code, but it is way harder to understand. A little improvement can get if bit-wise shifting is used:

    if (a != null) selector |= 1 << 0;
    if (b != null) selector |= 1 << 1;

  7. I think that depending on the case I would use either solution 1 or solution 2.
    But anyway, I would write solution 2 differently so that the 2 “sub-conditions” (the one with b) would be symetrical. By that I mean that in both case I’ll test b == null or I’ll test b != null but not once b == null and the time after b != null. I think this can lead to some (kinda stupid) errors.

  8. >I would write solution 2 differently
    I agree with you and in fact it was initially (in my code) wrote as you said. I changed it in fact for the post in order to respect the method call order defined in the problem declaration (in this declaration I wrote the order by changing only one condition between successive lines as in a binary table).

  9. > I agree with you about scalability. I’ll use this solution for that purpose.
    > About readability I think this one is the hardest to understand

    That’s what comments are for :-)

    case 0 : method1(); break; // a == null && b == null
    case 1 : method4(); break; // a == null && b != null

    The choice between “if (a != null) selector += 1;” or “if (a != null) selector |= 1 << 0;” is a matter of personal taste. They both mean exactly the same thing, i.e produce the exactly same result. If you have a math-oriented mind, the first choice is more readable; if you have a bit-oriented mind, take the second one. I, personally, prefer to think about powers of 2 than to think about bit fields, but the solutions are equivalent.

    Another totally different solution would be to use method “pointers”. This is easy to do in C/C++. But since there are no method pointers in Java, we have emulate this behaviour using reflection. It’s not as hard as it sounds. See http://www.javaworld.com/javaworld/jw-12-2000/jw-1221-reflection.html for an example.

  10. > How about using bit constants for this, instead of magic numbers?

    That’s an interesting, inteligent solution. The funny/awkward thing is that “case A_VALID|B_VALID” actually means “case A_VALID && B_VALID” (pseudo-code), i.e you use a bit-wise OR to mean a logical AND. This can be tricky to understand.

  11. The bad small is redundancy, in #1 more than in #2. Maybe it is a hint the coding is too functional instead of object-oriented, i.e. if the called methods are located in different classes and using template pattern you will not run in such problems.

  12. TheBrain: Yeah, but it’s common enough (e.g. creating SWT widgets) that most programmers should recognize it without problems (allthough it is a bit low-level and not very OOP-ish).

    The question would be, if the code wouldn’t be better if it used the “null object” pattern, which helps to eliminate null checks alltogether, but that depends on the specific situation (same with other patterns).

  13. Here is a one liner:
    String m = a == null ? (b == null ? “method1” : “method2”) : (b != null ? “method3” : “method4”);

    All you need to do next is to get the method using reflection and call it. I guess it’s not a one liner anymore then ;)

  14. Whenever I encounter solution 2 in a codebase, I usually refactor it to solution 1 because I find that much more readable than nested if statements. The code reduction benefit with solution 2 doesn’t outweigh the cost of slower readability in my opinion.

    I like the solution proposed with a switch statement, but while it makes code easier to write and scale, it also makes it slower and more difficult to read and understand compared to solution 1.

  15. I choose a simplified form of your second solution.

    if (a == null && b == null) {
    method1();
    } else if (a == null) {
    method2();
    } else if (b == null) {
    method3();
    } else {
    method4();
    }

  16. Pingback: VPS

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s