02 August 2009 ~ 37 Comments

If-else vs switch – Which is better?



"Use switch instead of if-else, its more readable and has better performance." I have to admit that this was one of my favorite code review comment. Until one fine day, while hacking Apache Sanselan's image format decoding function, I tried optimizing the code based on the same comments and while benchmark there was hardly any difference. I thought about investigating it further. Though found some interesting mail chains, though about posting my finding.

To begin with decided to run some samples on switch and if-else constructs and analyze further.

Wrote three function
1. For if-else - a if-else ladder based on int comparisons
2. For Switch - switch with 21 cases, from 1 to 20
3. For Switch - switch with sparse random values

The reason for choosing two functions for switch was this statement from VM spec "Compilation of switch statements uses the tableswitch and lookupswitch instructions"

Lets see the function codes

if-else

public static void testIfElse(int jumpLabel) {
if(1 == jumpLabel) {
    System.out.println("1");
} else if(2 == jumpLabel) {
    System.out.println("2");
} else if(3 == jumpLabel) {
    System.out.println("3");
} else if(4 == jumpLabel) {
    System.out.println("4");
}
// Removed for simplicity
else {
    System.out.println("default");
}
}


Lets see the switch functions

Finite switch version

public static void testSwitchFinite(int jumpLable) {

switch (jumpLable) {
case 1:
    System.out.println("1");
    break;

case 2:
    System.out.println("2");
    break;

case 3:
    System.out.println("3");
    break;

case 4:
    System.out.println("4");
    break;

case 5:
    System.out.println("5");
    break;

// Removed other cases for simplicity

default:
    System.out.println("default");
    break;
}
}


Sparse switch version

public static void testSwitchSparse(int jumpLable) {

switch (jumpLable) {
case 100:
    System.out.println("1");
    break;

case -1:
    System.out.println("2");
    break;

case 5000:
    System.out.println("3");
    break;

case -8:
    System.out.println("4");
    break;

case 1600:
    System.out.println("5");
    break;

case 250:
    System.out.println("250");
    break;

// Removed other cases for simplicity

default:
    System.out.println("default");
    break;
}
}


With the groundwork done, its the benchmarking time. The benchmarking strategy was simple. Run these functions in loop and see the result, with iteration ranging from 100 to 1000.

Lets look at one of the functions

public static void testSwitchPerf(int iteration) {
    long t1 = System.nanoTime();
    for (int i = 0; i < iteration; i++) {
        testSwitchFinite(i);
    }
    long t2 = System.nanoTime();
    System.out.println("Time Taken (switch) = "+(t2 - t1)/1000000);
}

Well this was the ground work, after executing the conditions, here is the data

Iteration -> 100 1000
if-else 8 ms 69 ms
switch finite 3 ms 34 ms
switch sparse 7 ms 21 ms

NOTE: There is some difference due to the way data is provided and the sample space doesn't provide precise results. However, since the sample space is same for both, it would serve its purpose


Conclusion

1. There is no significant execution difference between if-else and switch. The difference observed is due to the sample space choosen.
2. If using if-else, its always recommended to put frequently used if condition at the top of if-else ladder
3. The finite switch statement was converted to tableswitch and sparse switch was converted to lookupswitch

would be interested to hear from folks about their experience in relation to this. I would say, i still prefer switch for readability. Henceforth, my review comment shall be modified as "Use switch instead of if-else, its more readable and has better performance"

Share your thoughts

I would be very keen to hear from you all, about your opinions and experience about the topic


37 Responses to “If-else vs switch – Which is better?”

  1. Bob 3 August 2009 at 7:58 am Permalink

    looks to me like the switch statement has much better performance. It looks like 20-50+ cycles per evaluation faster.

    • ashish 3 August 2009 at 5:23 pm Permalink

      Bob, indeed it is. However, my view was more towards an average programming environment.

  2. SeanJA 3 August 2009 at 9:12 am Permalink

    I would disagree with the more readable part of switch. While yes, in the simplest of cases it is more readable, it becomes significantly less readable as you add to the complexity of the statements within.

    • ashish 3 August 2009 at 5:25 pm Permalink

      Hmm, more or less, I find switch more readable than if-else. However, the ode becomes ugly, if you putin too much into a case.

      • Stein-Bjarne Johansen 14 November 2013 at 7:19 pm Permalink

        I don’t agree with the statement that it depends how much you put into a case. If anything more than 3-4 lines per case, then it should be put into a private function/method anyways.

        • andrew 24 January 2014 at 1:11 pm Permalink

          How does having it in a function make it neater??? You still going to need the case and when there are a lot of lines it looks messy. I personally prefer an if statement for readability and its far more versatile.

          • Miles 28 January 2014 at 4:33 am Permalink

            Regardless of how it looks, it is a good practice to break up functionality into smaller methods. Plus it should be neater if all you have in a switch is a few lines executing methods/functions vs cramming everything in.

            This approach should also be applied in if-else if-else trees as well though.

  3. Scott 3 August 2009 at 9:39 am Permalink

    I work on a high performance server project at a very very larger computer company and if you told me in a department meeting that there was no difference between 8ms and 3ms you would be laughed out of the room.

    Besides that, your example is in Java which is interpreted byte code. Each JVM performs differently depending on the implementation (Sun,IBM,etc) and platform. Throwing that completely aside, your assumptions or conclusions may not hold up for other binary languages like C/C++.

    In the end benchmarking can only be done on a per-configuration basis. There are too many variables here to say that using an If-else vs a switch has any other impacts than readability/maintainability, when their side-effects are quiet different and while their semantics are similar their usage is called for in different scenarios and aren’t even completely comparable.

    Each job as a different tool to solve it.

    Just my $0.02.

    • ashish 3 August 2009 at 5:27 pm Permalink

      Scott, I absolutely agree with you. And If I had been working for you, I would have never said that :-)

      You have brought in an excellent view here and I shall explore further on this.
      Appreciate your taking time to post a comment.

      Thanks

  4. Ben Kovitz 3 August 2009 at 9:52 am Permalink

    Isn’t a factor of 2 or more a significant improvement in performance?

    • ashish 3 August 2009 at 5:28 pm Permalink

      Yup, but the benchmarks are not very accurate

  5. Ben Manes 3 August 2009 at 10:15 am Permalink

    A switch statement over an if-else clause is definately better if the code is being executed millions of times. In the aggregate the performance is noticable. I recently changed code that was under heavy use from if-else clauses to map-based switch statements (e.g. Class -> Function) and saw a nice improvement. The code wasn’t as readable, since the map needed to be created statically, but given the usage patterns it was a worthwhile change.

    • ashish 3 August 2009 at 5:29 pm Permalink

      Ben, Thanks for the input. I ran the benchmark only couple of hundreds times. And yes in millions iteration, the performance would really add up a lot.

  6. agit8d 3 August 2009 at 10:40 am Permalink

    100% more elapsed time (on average?) for an if-else branch is very significant. But that doesn’t even matter, because you never bother to elaborate on how data is provided, why it makes a difference and then you’re sampling with nanoTime() – known to provide 0 accuracy guarantees.

    Do a real benchmark.

    .02c

    • ashish 3 August 2009 at 5:31 pm Permalink

      Think, I have put the function used to get the data and the data has number of iterations as well.
      Though your point of nanoseconds is valid.

      Will try to go for a better benchmark.
      Thanks

  7. Pierre-Julien 3 August 2009 at 4:29 pm Permalink

    Your benchmark is not very useful: System.out.println is the costly operation in your loop, it looks like you’re measuring randomness. Could you publish standard deviation, and the number of tests you ran at least to provide some sort of idea of the reliability of these measures?

    • ashish 3 August 2009 at 5:32 pm Permalink

      Good Idea. We can ignore the Sysout’s as its presents for both the executions.
      let me work on it further.

      Thanks for the pointers.

  8. gorlok 3 August 2009 at 5:06 pm Permalink

    In general, forget about nanooptimization like this. It’s a bad idea.
    First, wrote easy to read code. Then, *if needed*, profile it.
    My 2 cts.

    • ashish 3 August 2009 at 5:33 pm Permalink

      Thanks! That’s what I often tell people to avoid this syndrome.

  9. Jan Van Besien 3 August 2009 at 5:16 pm Permalink

    You should really read some stuff about micro benchmarking first, before diving into it. This is a good start:

    http://www.ibm.com/developerworks/java/library/j-jtp02225.html

    • ashish 3 August 2009 at 5:33 pm Permalink

      Thanks for the pointer. Will definitely work more on this.

  10. Shaun 3 August 2009 at 6:12 pm Permalink

    I realize you probably weren’t using real world examples (I hope not, anyway), but even so with these examples I’d say if you have code that looks anything like this then its a good bet your abstraction is on shaky ground to begin with and that optimization is probably the least of your concerns.

    The problem is that either of these are too brittle in the face of change. Find a higher abstraction first, then optimize.

    • ashish 4 August 2009 at 6:38 am Permalink

      Thanks Shaun for the pointer. However, my objective here was very simple to see which is better. Most cases that I encounter, there are typically 5-8 conditions. Well, I just wanted to check that what I understand is really true under what circumstances.

  11. kirk 4 August 2009 at 11:18 am Permalink

    This bench is busted. First, get rid of the writing to console. It’s activity will completely dominate the profile. Secondly, I’d take a look at the byte code. I think you’ll find that sparse switch and if-else get about the same byte code so there should be no difference. The range will be a calculated goto and so the result of the bench will be completely dependent on the ordering of the data.

    There is no such thing as a simple microbenchmark.

    Regards,
    Kirk

    • ashish 4 August 2009 at 8:19 pm Permalink

      Thanks Kirk! My simple objective was to evaluate my review comment “Which is better” in general context. Console IO is present for both. So the conditions are similar for both cases.

  12. kirk 4 August 2009 at 11:19 am Permalink

    I forgot to mention the timings are well within the range that you are measuring randomness. Any benchmark needs to be run for a significant period of time to dampen out the resolution of the clock and the cost of getting that measurement.

  13. scot 4 August 2009 at 11:43 am Permalink

    First, microbenchmarks are a waste of time.

    Second, as Shaun says above, using either switch or if-else especially for more than the most trivial of cases is a very good indicator your code is in poor shape and requires redesigning. There is no “better” in this circumstance. Either way it is a pointer to a failure to apply the many well-known and well-proven techniques of object orientated design.

  14. ppow 4 August 2009 at 4:22 pm Permalink

    Why are you doing the benchmarking with System.out.printlns?? This is strongly affecting the results you are getting as this is a really time consuming operation. Maybe try to replace it with any other non-trivial opp (so that the compiler does not optimize your code and skip if-else or switch) or try to subtracts from the result the costs of System.out.println?

    BTW: this is a really interesting topic, let me know about what you’ll do next :)

    • ashish 4 August 2009 at 8:22 pm Permalink

      Well Sysouts are present in both cases and its comparative. Since conditions are same, both emit output to console. So this was fine in my case.
      Not sure what’s next, right now hacking Apache Vysper code.

  15. Ray 5 August 2009 at 9:17 pm Permalink

    The biggest benefit I tell junior programmers, in support of switch statement, is IDE support. If you add an item to an Enumeration, many IDEs will warn you that it is not being used in your switch statement. So the IDE is helping you ensure that your forking code is correct. With if/else, you have to search through the code and hope you don’t make a mistake.

    So to me, this is a readability and maintenance issue.

  16. ksongking 18 August 2009 at 7:51 am Permalink

    Since many expects are here. I did try to benchmark in between if/else and switch case before. I agreed on switch case is faster than the if/else case, but normally the test is taking the avarage measurement for both statements to get matched. Last time when i did my test, i found another finding, i was using Bios/DSP and use the ADI provided compiler to benchmark the cycle counts for both statements, i found that, the switch statement is faster than the if/else statement. But, the time to match the first case in switch is the same with the time to match the last case, or the default case of the switch, so, regardless which case i matched in the switch statement, it will take the constant cycle times to run the who switch statement, and the cycle time is increasing if there are more case added in, my finding is, for switch statement, the time spent to match any cases is the same, there has no advantage even the first case is matched. Compare to the if/else statement, the last matching condition always take much than the switch, but if the condition always hit the first or second condition, then the cycle time reduced very much, so normally when using the if/else statement, we will prioritize the most likely happen case on top, this can really speed up the comparison compare to switch case since no matter which case it will be matched, the time taken will be constantly long, and it consume more MIPS when more cases added in. Please verify my finding.

  17. AKriauciunas 26 May 2010 at 2:39 am Permalink

    I didn’t see anyone mention the underlying issue when dealing with compiled code – whenever you don’t know for sure what the next statement is going to be (at the machine code level), the compiler will have to insert a few (typically 2-3) NOPs to flush the pipeline. I believe the systems I worked on (Ti DSP processors) used 2-3 NOPs to do this. So, all things being equal, every time you evaluate an if/else you have a few wasted instruction cycles. The switch absorbs the overhead once when it looks up the jump offset in the jump table. So, the real question is at which point does the variable overhead (flushing the pipeline every time you see an if statement) outweigh the slightly higher fixed overhead (computing the jump offset). If your algorithm is on the critical path in a real-time environment, these are definitely important issues.

  18. Yves 19 July 2011 at 3:08 pm Permalink

    Hmm tried it in a real world application, which was performing different tasks in a loop on a given number (30 else ifs – from 0 to 29). After optimizing it to switch case, i tested the performance again (with the same data) and didn’t get any changess.

  19. Carlos 6 January 2012 at 8:59 am Permalink

    Have you tried coding if-else statements a bit differently?
    Your example needs O(n) comparisons, (being n the number of labels to compare) to execute.

    Suppose you had 2n (V1…V2n) values to compare and you code something that would work like a binary search.

    the first if test would compare against the label that is half the grup, the second comparison would test agaist a quarter value aand so forth until the lowest level which would be a regular straightforward one-by-one if-else of a small group of 4 values. (like your example)

    Assume you had 200 labels. the first comparison will discard 100 values. next nested if will discard 50 more. the next will discard 25.

    As a result, by making just three comparisons you have only 25 possible candidates out of 200. now at this point you can use your regular comparison code. And that is O(n/4).

    Suggest you to re-run the test now using large sets of values. (200+)

    if (jumplabel < Vn) then
    if (jumplabel < Vn/2) then


    if
    else

  20. Johnny Boy 6 February 2014 at 11:54 am Permalink

    You have a good article, but I don’t see any mention of the Ternary Operator ?: in C#. Here’s a blog which benchmarks the if/else, switch/case, and ternary operator:

    http://blogs.davelozinski.com/curiousconsultant/c-sharp-net-what-is-the-fastest-conditional-statement

    and determines which was is the fastest.

    Definitely worth a read like yours.

    Keep up the great posts!

  21. Steven 12 February 2014 at 9:33 pm Permalink

    I generally prefer switch over a chain of if/else because the situations in which I would need to choose don’t usually warrant the extra functionality of an if statement.

    I work in C# a lot and the parameters of a case statement must be constant values. When you have a single variable and you want to check it for X specific values or run a default code for any other value, switch/case just makes sense.

    If/Else is a lot more powerful because each if/else statement can evaluate just about anything you want as long as it returns true or false. You can do type checking or pass the parameter through a method while you’re checking, etc. To me it’s a strange comparison because chaining if/else statements is somewhat unrelated to a switch statement; it just so happens that you can mimic the functionality of a switch statement with a chain of if/else statements.

    As far as readability goes I see no advantage to either. If you write your if/else statements in a readable way there shouldn’t be a problem. I have no idea why, in PHP and JavaScript for example, people write statements with their leading brackets right in front of the statement. This is just silly to me. The brackets belong underneath the initial statement and the code within them should be indented. I’d like to know one logical reason anyone would do otherwise. For Example:

    function myFunction($input)
    {
    $var = 1;

    if($var == $input)
    {
    print(“Values are Equal!”);
    }
    }

    That makes sense because the beginning and ending curly brackets are in line with each other so it’s easier to tell where they pair up. Anyway, that’s my 2¢.


Leave a Reply