Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: instanceof vs class name switch performance

I was interested in performance question about determine type of object and write some benchmarks with 2 ways of determination.

Can someone explain me why variant with instanceof faster 350 times than variant with class name switching with strings?

Code:

class A {}
class B extends A {}

public class InstanceOfBenchmark {
    public static final Object a = new A();

    @Benchmark
    @BenchmarkMode(Mode.Throughput)
    @OutputTimeUnit(TimeUnit.MICROSECONDS)
    public void testInstanceOf()
    {
        if (a instanceof B) {}
        else if (a instanceof String) {}
        else if (a instanceof ArrayList) {}
        else if (a instanceof HashMap) {}
        else if (a instanceof HashSet) {}
        else if (a instanceof A);
    }

    @Benchmark
    @BenchmarkMode(Mode.Throughput)
    @OutputTimeUnit(TimeUnit.MICROSECONDS)
    public void testName() {
        String class_name = a.getClass().getSimpleName();

        switch (class_name) {
            case ("B") :
            case ("String") :
            case ("ArrayList") :
            case ("HashMap") :
            case ("HashSet") :
            case ("A") :
        }
    }

    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(InstanceOfBenchmark.class.getSimpleName())
                .warmupIterations(20)
                .measurementIterations(100)
                .forks(1)
                .build();

        new Runner(opt).run();
    }
}

Results:

Benchmark                            Mode  Cnt     Score    Error   Units
InstanceOfBenchmark.testInstanceOf  thrpt  100  3482.001 ± 25.447  ops/us
InstanceOfBenchmark.testName        thrpt  100    10.579 ±  0.078  ops/us

I run tests with 200 times warmup and 2000 iteration too, result was same.

like image 561
mikewoe Avatar asked Jun 20 '18 10:06

mikewoe


1 Answers

Bytecode for the String version:

   0: aload_0
   1: invokevirtual #2           // Method java/lang/Object.getClass:()Ljava/lang/Class;
   4: invokevirtual #3           // Method java/lang/Class.getSimpleName:()Ljava/lang/Str
   7: astore_1
   8: aload_1
   9: astore_2
  10: iconst_m1
  11: istore_3
  12: aload_2
  13: invokevirtual #4           // Method java/lang/String.hashCode:()I
  16: lookupswitch  { // 6
       -1932803762: 118
       -1932797868: 132
       -1808118735: 90
                65: 146
                66: 76
         578806391: 104
           default: 157
      }
  76: aload_2
  77: ldc           #5           // String B
  79: invokevirtual #6           // Method java/lang/String.equals:(Ljava/lang/Object;)Z
  82: ifeq          157
  85: iconst_0
  86: istore_3
  87: goto          157
  90: aload_2
  91: ldc           #7          // String String
  93: invokevirtual #6          // Method java/lang/String.equals:(Ljava/lang/Object;)Z
  96: ifeq          157
  99: iconst_1
 100: istore_3
 101: goto          157
 104: aload_2
 105: ldc           #8          // String ArrayList
 107: invokevirtual #6          // Method java/lang/String.equals:(Ljava/lang/Object;)Z
 110: ifeq          157
 113: iconst_2
 114: istore_3
 115: goto          157
 118: aload_2
 119: ldc           #9           // String HashMap
 121: invokevirtual #6           // Method java/lang/String.equals:(Ljava/lang/Object;)Z
 124: ifeq          157
 127: iconst_3
 128: istore_3
 129: goto          157
 132: aload_2
 133: ldc           #10           // String HashSet
 135: invokevirtual #6            // Method java/lang/String.equals:(Ljava/lang/Object;)Z
 138: ifeq          157
 141: iconst_4
 142: istore_3
 143: goto          157
 146: aload_2
 147: ldc           #11           // String A
 149: invokevirtual #6            // Method java/lang/String.equals:(Ljava/lang/Object;)Z
 152: ifeq          157
 155: iconst_5
 156: istore_3
 157: iload_3
 158: tableswitch   { // 0 to 5
                 0: 196
                 1: 196
                 2: 196
                 3: 196
                 4: 196
                 5: 196
           default: 196
      }
 196: return

Bytecode for the instanceof version:

  0: aload_0
  1: instanceof    #12                 // class B
  4: ifeq          10
  7: goto          57
 10: aload_0
 11: instanceof    #13                 // class java/lang/String
 14: ifeq          20
 17: goto          57
 20: aload_0
 21: instanceof    #14                 // class java/util/ArrayList
 24: ifeq          30
 27: goto          57
 30: aload_0
 31: instanceof    #15                 // class java/util/HashMap
 34: ifeq          40
 37: goto          57
 40: aload_0
 41: instanceof    #16                 // class java/util/HashSet
 44: ifeq          50
 47: goto          57
 50: aload_0
 51: instanceof    #17                 // class A
 54: ifeq          57
 57: return

Does it still surprise you that instanceof is faster? The number of operations is significantly fewer.

like image 83
Michael Avatar answered Nov 09 '22 23:11

Michael