What is the relative performance difference of if/else versus switch statement in Java?

127,580

Solution 1

That's micro optimization and premature optimization, which are evil. Rather worry about readabililty and maintainability of the code in question. If there are more than two if/else blocks glued together or its size is unpredictable, then you may highly consider a switch statement.

Alternatively, you can also grab Polymorphism. First create some interface:

public interface Action { 
    void execute(String input);
}

And get hold of all implementations in some Map. You can do this either statically or dynamically:

Map<String, Action> actions = new HashMap<String, Action>();

Finally replace the if/else or switch by something like this (leaving trivial checks like nullpointers aside):

actions.get(name).execute(input);

It might be microslower than if/else or switch, but the code is at least far better maintainable.

As you're talking about webapplications, you can make use of HttpServletRequest#getPathInfo() as action key (eventually write some more code to split the last part of pathinfo away in a loop until an action is found). You can find here similar answers:

If you're worrying about Java EE webapplication performance in general, then you may find this article useful as well. There are other areas which gives a much more performance gain than only (micro)optimizing the raw Java code.

Solution 2

I totally agree with the opinion that premature optimization is something to avoid.

But it's true that the Java VM has special bytecodes which could be used for switch()'s.

See WM Spec (lookupswitch and tableswitch)

So there could be some performance gains, if the code is part of the performance CPU graph.

Solution 3

It's extremely unlikely that an if/else or a switch is going to be the source of your performance woes. If you're having performance problems, you should do a performance profiling analysis first to determine where the slow spots are. Premature optimization is the root of all evil!

Nevertheless, it's possible to talk about the relative performance of switch vs. if/else with the Java compiler optimizations. First note that in Java, switch statements operate on a very limited domain -- integers. In general, you can view a switch statement as follows:

switch (<condition>) {
   case c_0: ...
   case c_1: ...
   ...
   case c_n: ...
   default: ...
}

where c_0, c_1, ..., and c_N are integral numbers that are targets of the switch statement, and <condition> must resolve to an integer expression.

  • If this set is "dense" -- that is, (max(ci) + 1 - min(ci)) / n > α, where 0 < k < α < 1, where k is larger than some empirical value, a jump table can be generated, which is highly efficient.

  • If this set is not very dense, but n >= β, a binary search tree can find the target in O(2 * log(n)) which is still efficient too.

For all other cases, a switch statement is exactly as efficient as the equivalent series of if/else statements. The precise values of α and β depend on a number of factors and are determined by the compiler's code-optimization module.

Finally, of course, if the domain of <condition> is not the integers, a switch statement is completely useless.

Solution 4

Use switch!

I hate to maintain if-else-blocks! Have a test:

public class SpeedTestSwitch
{
    private static void do1(int loop)
    {
        int temp = 0;
        for (; loop > 0; --loop)
        {
            int r = (int) (Math.random() * 10);
            switch (r)
            {
                case 0:
                    temp = 9;
                    break;
                case 1:
                    temp = 8;
                    break;
                case 2:
                    temp = 7;
                    break;
                case 3:
                    temp = 6;
                    break;
                case 4:
                    temp = 5;
                    break;
                case 5:
                    temp = 4;
                    break;
                case 6:
                    temp = 3;
                    break;
                case 7:
                    temp = 2;
                    break;
                case 8:
                    temp = 1;
                    break;
                case 9:
                    temp = 0;
                    break;
            }
        }
        System.out.println("ignore: " + temp);
    }

    private static void do2(int loop)
    {
        int temp = 0;
        for (; loop > 0; --loop)
        {
            int r = (int) (Math.random() * 10);
            if (r == 0)
                temp = 9;
            else
                if (r == 1)
                    temp = 8;
                else
                    if (r == 2)
                        temp = 7;
                    else
                        if (r == 3)
                            temp = 6;
                        else
                            if (r == 4)
                                temp = 5;
                            else
                                if (r == 5)
                                    temp = 4;
                                else
                                    if (r == 6)
                                        temp = 3;
                                    else
                                        if (r == 7)
                                            temp = 2;
                                        else
                                            if (r == 8)
                                                temp = 1;
                                            else
                                                if (r == 9)
                                                    temp = 0;
        }
        System.out.println("ignore: " + temp);
    }

    public static void main(String[] args)
    {
        long time;
        int loop = 1 * 100 * 1000 * 1000;
        System.out.println("warming up...");
        do1(loop / 100);
        do2(loop / 100);

        System.out.println("start");

        // run 1
        System.out.println("switch:");
        time = System.currentTimeMillis();
        do1(loop);
        System.out.println(" -> time needed: " + (System.currentTimeMillis() - time));

        // run 2
        System.out.println("if/else:");
        time = System.currentTimeMillis();
        do2(loop);
        System.out.println(" -> time needed: " + (System.currentTimeMillis() - time));
    }
}

My C# standard code for benchmarking

Solution 5

I remember reading that there are 2 kinds of Switch statements in Java bytecode. (I think it was in 'Java Performance Tuning' One is a very fast implementation which uses the switch statement's integer values to know the offset of the code to be executed. This would require all integers to be consecutive and in a well-defined range. I'm guessing that using all the values of an Enum would fall in that category too.

I agree with many other posters though... it may be premature to worry about this, unless this is very very hot code.

Share:
127,580
Anth0
Author by

Anth0

Fullstack software craftsman

Updated on July 08, 2022

Comments

  • Anth0
    Anth0 almost 2 years

    Worrying about my web application's performances, I am wondering which of "if/else" or switch statement is better regarding performance?

    • Pascal Cuoq
      Pascal Cuoq over 14 years
      Do you have any reason to think the same bytecode is not generated for the two constructs?
    • jldupont
      jldupont over 14 years
      @Pascal: there might be optimization done by using table look-ups instead of a list of if etc.
    • missingfaktor
      missingfaktor over 14 years
      "Premature optimization is the root of all evil" - Donald Knuth
    • Leo Jweda
      Leo Jweda over 14 years
      You should give this a read.
    • Lawrence Dol
      Lawrence Dol over 14 years
      While this is definitely premature optimization, "Mindless adherence to a quote taken badly out of context is the reason we need a high-end multi-core computer just to display a reasonably responsive GUI today" - Me.
    • Kevin Bourrillion
      Kevin Bourrillion over 14 years
      These questions will never stop.
    • alphazero
      alphazero about 13 years
      Knuth has a precise mind. Please note the qualifier "premature". Optimization is a perfectly valid concern. That said, a server is IO bound and the bottlenecks of network and disk I/O are orders of magnitude more significant than anything else you have going on in your server.
    • Ciro Santilli OurBigBook.com
      Ciro Santilli OurBigBook.com almost 9 years
      @PascalCuoq javap and the javac source code: stackoverflow.com/a/31032054/895245
    • Archimedes Trajano
      Archimedes Trajano about 7 years
      Try using caliper to microbenchmark your code. If you're doing it for optimization then I would agree with the sentiment of others that it isn't a good idea, but as an educational exercise it would be nice to see. Check trajano.net/2014/08/… for an example
    • Emmanuel
      Emmanuel almost 3 years
      @LawrenceDol This question is a decade late but is there a story you're referring to with the high-end computer GUI comment?
    • Lawrence Dol
      Lawrence Dol almost 3 years
      @Emmanuel : No story. Just making the counterpoint to the Knuth quote which, as usual, is stripped of its context and used as a blunt excuse to write crappy code.
  • Adam Paynter
    Adam Paynter over 14 years
    +1. There is a good chance that time spent on network I/O is easily eclipsing this particular issue.
  • jk.
    jk. over 14 years
    or consider polymorphism instead
  • BalusC
    BalusC over 14 years
    That's indeed more recommended in case of "unpredictable" amount of if/else blocks.
  • user1568901
    user1568901 over 14 years
    I'm not so quick to dismiss all early optimization as "evil". Being too aggressive is foolish, but when faced with constructs of comparable readability choosing one known to perform better is an appropriate decision.
  • x4u
    x4u over 14 years
    The HashMap lookup version can easily be 10 times slower compared to a tableswitsch instruction. I wouldn't call this "microslower"!
  • BalusC
    BalusC over 14 years
    I mean, slower in terms of "microseconds".
  • Folkert van Heusden
    Folkert van Heusden almost 12 years
    I wonder why this comment isn't rated higher: it is the most informitive of all of them. I mean: we all already know about premature optimalization being bad and such, no need to explain that for the 1000th time.
  • KingAndrew
    KingAndrew over 10 years
    +1 for the hot code comment. If its in your main loop its not premature.
  • DerMike
    DerMike about 10 years
    Could you please (sometime) elaborate a bit on how you did benchmark this?
  • DerMike
    DerMike about 10 years
    Thank you very much for your update. I mean, they differ by one order of magnitude - wich is possible of course. Are you sure that the compiler did not just optimze the switches away?
  • Bitterblue
    Bitterblue about 10 years
    @DerMike I don't remember how I got the old results. I got very different today. But try it yourself and let me know how it turns out.
  • caw
    caw almost 10 years
    +1 As of stackoverflow.com/a/15621602/89818 it seems the performance gains are really there, and you should see an advantage if you use 18+ cases.
  • atraudes
    atraudes over 9 years
    It should be noted that switches work with more than just ints. From the Java Tutorials: "A switch works with the byte, short, char, and int primitive data types. It also works with enumerated types (discussed in Enum Types), the String class, and a few special classes that wrap certain primitive types: Character, Byte, Short, and Integer (discussed in Numbers and Strings)." Support for String is more recent addition; added in Java 7. docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.htm‌​l
  • Kanagavelu Sugumar
    Kanagavelu Sugumar over 9 years
    @jhonFeminella Could you please compare BIG O notion effects for Java7 String in Swtich compared to String in if / else if ..?
  • Hot Licks
    Hot Licks over 9 years
    Yes, javac implements switch several different ways, some more efficient than others. In general, the efficiency will be no worse than a straight-forward "if ladder", but there are enough variations (especially with the JITC) that it's hard to be much more precise than that.
  • halil
    halil about 9 years
    when i run it on my laptop ; switch time needed: 3585, if/else time needed: 3458 so if/else is better :) or not worse
  • halil
    halil about 9 years
    Time taken for String in Switch :3235 Time taken for String in if/else if :3143 Time taken for String in Map :4194 Time taken for String in ENUM :2866
  • Bitterblue
    Bitterblue about 9 years
    @halil 2nd sentence of the accepted answer is absolutely right. In your case I would take switch anyways. The times aren't that different.
  • searchengine27
    searchengine27 about 9 years
    I'm interested in actually knowing the inner workings of Java in the general case with switch statements - I'm not interested in whether or not somebody thinks this is related to over-prioritizing early optimization. That being said, I have absolutely no idea why this answer is upvoted so much and why it is the accepted answer...this does nothing to answer the initial question.
  • Kanagavelu Sugumar
    Kanagavelu Sugumar almost 9 years
    @halil I am not sure how this code works on different environments, but you have mentioned if/elseif is better than Switch and Map, that i am not able to convince since if/elseif has to perform more no of times equals comparison.
  • Ciro Santilli OurBigBook.com
    Ciro Santilli OurBigBook.com almost 9 years
    More precisely, javac 8 gives a weight of 3 to time complexity over space complexity: stackoverflow.com/a/31032054/895245
  • WhilseySoon
    WhilseySoon about 8 years
    You could use break instead of these else-if statements though.
  • boneill
    boneill almost 8 years
    The dominant cost in the test is the random number generation. I modified the test to generate the random number before the loop, and used the temp value to feed back into r. The switch is then almost twice as fast as the if-else chain.
  • AmeyaB
    AmeyaB about 7 years
    Inaccurate.., the random number should be generated before and same one should be fed to both the methods.
  • D. L.
    D. L. about 7 years
    As others remarked, random is costly and hides differences in performance. I replaced int r = (int) (Math.random() * 10); with int r = (loop & 0b11111) != 0b0 ? 0 : loop % 10; and got that the if/else is three times as fast as the switch, which shows it also depends on the distribution of your data.