Backend Development 16 min read

Why Switch Beats If‑Else in Java: Up to 3.7× Faster (JMH Benchmark)

This article benchmarks Java's switch statement against equivalent if‑else chains using JMH, explains the underlying bytecode differences, shows how tableswitch and lookupswitch are generated, and demonstrates that switch can be up to 3.7 times faster as the number of branches grows.

macrozheng
macrozheng
macrozheng
Why Switch Beats If‑Else in Java: Up to 3.7× Faster (JMH Benchmark)

switch VS if

Conditional statements are a core part of program logic, and choosing between

if

and

switch

can impact performance. This article uses the JMH (Java Microbenchmark Harness) framework to compare their execution times.

JMH Setup

<code><!-- https://mvnrepository.com/artifact/org.openjdk.jmh/jmh-core -->
<dependency>
   <groupId>org.openjdk.jmh</groupId>
   <artifactId>jmh-core</artifactId>
   <version>1.23</version>
</dependency>
</code>

We create a benchmark class with five conditional branches:

<code>import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.concurrent.TimeUnit;

@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 2, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(1)
@State(Scope.Thread)
public class SwitchOptimizeTest {
    static Integer _NUM = 9;

    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(SwitchOptimizeTest.class.getSimpleName())
                .output("/Users/admin/Desktop/jmh-switch.log")
                .build();
        new Runner(opt).run();
    }

    @Benchmark
    public void switchTest() {
        int num1;
        switch (_NUM) {
            case 1:  num1 = 1; break;
            case 3:  num1 = 3; break;
            case 5:  num1 = 5; break;
            case 7:  num1 = 7; break;
            case 9:  num1 = 9; break;
            default: num1 = -1; break;
        }
    }

    @Benchmark
    public void ifTest() {
        int num1;
        if (_NUM == 1) { num1 = 1; }
        else if (_NUM == 3) { num1 = 3; }
        else if (_NUM == 5) { num1 = 5; }
        else if (_NUM == 7) { num1 = 7; }
        else if (_NUM == 9) { num1 = 9; }
        else { num1 = -1; }
    }
}
</code>

The benchmark results (image omitted) show that the average execution time of

switch

is about 2.33 times faster than

if

for five branches.

Performance Analysis

Bytecode generated by

javac

reveals why:

<code>public class com.example.optimize.SwitchOptimize {
  static java.lang.Integer _NUM;
  public static void switchTest() {
    getstatic #15 // _NUM
    invokevirtual #19 // intValue()
    tableswitch { // 1 to 9
      1: 56
      2: 61
      3: 66
      4: 71
      5: 76
      6: 81
      7: 87
      8: 93
      9: 99
      default: 105
    }
    ...
  }
  public static void ifTest() {
    getstatic #15 // _NUM
    invokevirtual #19 // intValue()
    iconst_1
    if_icmpne 15
    ...
  }
}
</code>

In the

switch

bytecode the variable is fetched once (

getstatic #15

) and the value is compared via a

tableswitch

. In the

if

version the variable is fetched and compared for each branch, leading to more instructions and slower execution.

Increasing the Number of Branches

When the number of branches is increased threefold (15 cases), the performance gap widens:

switch

becomes about 3.7 times faster than

if

.

switch’s Secret: tableswitch vs lookupswitch

Depending on how compact the case values are, the compiler emits either a

tableswitch

(dense range) or a

lookupswitch

(sparse values). The following code demonstrates both:

<code>public class SwitchOptimize {
    static Integer _NUM = 1;
    public static void tableSwitchTest() {
        int num1;
        switch (_NUM) {
            case 1: num1 = 1; break;
            case 2: num1 = 2; break;
            case 3: num1 = 3; break;
            case 4: num1 = 4; break;
            case 5: num1 = 5; break;
            case 6: num1 = 6; break;
            case 7: num1 = 7; break;
            case 8: num1 = 8; break;
            case 9: num1 = 9; break;
            default: num1 = -1; break;
        }
    }
    public static void lookupSwitchTest() {
        int num1;
        switch (_NUM) {
            case 1:  num1 = 1; break;
            case 11: num1 = 2; break;
            case 3:  num1 = 3; break;
            case 4:  num1 = 4; break;
            case 19: num1 = 5; break;
            case 6:  num1 = 6; break;
            case 33: num1 = 7; break;
            case 8:  num1 = 8; break;
            case 999:num1 = 9; break;
            default: num1 = -1; break;
        }
    }
}
</code>

The generated bytecode shows a

tableswitch

for the dense case set and a

lookupswitch

for the sparse set.

tableswitch

works like an array lookup (O(1)), while

lookupswitch

performs a binary search (O(log n)), making the former faster.

Benchmarking both shows that for nine branches

tableswitch

is about 1.3× faster than

lookupswitch

, yet both outperform

if

by a large margin.

Conclusion

For five branches,

switch

is roughly 2.3× faster than

if

. As the number of branches grows, the performance advantage of

switch

becomes more pronounced. The Java compiler emits

tableswitch

for compact case ranges and

lookupswitch

for sparse ones; the former is faster due to its array‑like indexing, but regardless,

switch

consistently outperforms

if

in execution speed.

Test environment: JDK 1.8 / Mac mini (2018) / IntelliJ IDEA 2020.1
Javaperformancebytecodeif-elseJMHswitch
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.