为什么说在使用多条件判断时switch case语句比if语句效率高?

  在学习JavaScript中的if控制语句和switch控制语句的时候,提到了使用多条件判断时switch case语句比if语句效率高,但是身为小白的我并没有在代码中看出有什么不同。去度娘找了半个小时,看了各位大神的表述,找到一个比较清晰的文章。

  原来,switch进行了跳转优化,java中对switch有两种处理方式,生成不同的jvm指令,一是tableswitch,一个是lookupswitch。对于case的分支比较密集的情况,如:

public class Test {
 
    public static void main(String[] args) {
        int i = 3;
        switch (i) {
            case 0:
                System.out.println("0");
                break;
            case 1:
                System.out.println("1");
                break;
            case 3:
                System.out.println("3");
                break;
            case 5:
                System.out.println("5");
                break;
            case 10:
                System.out.println("10");
                break;
            case 13:
                System.out.println("13");
                break;
            case 14:
                System.out.println("14");
                break;
        default:
        System.out.println("default");
                break;
        }
 
 
    }
}

使用tableswitch,得到:

public static void main(java.lang.String[]);
  Code:
   0:    iconst_3
   1:    istore_1
   2:    iload_1
   3:    tableswitch{ //0 to 14
        0: 76;
        1: 87;
        2: 153;
        3: 98;
        4: 153;
        5: 109;
        6: 153;
        7: 153;
        8: 153;
        9: 153;
        10: 120;
        11: 153;
        12: 153;
        13: 131;
        14: 142;
        default: 153 }
   76:    getstatic    #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   79:    ldc    #3; //String 0
   81:    invokevirtual    #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   84:    goto    161
   87:    getstatic    #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   90:    ldc    #5; //String 1
   92:    invokevirtual    #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   95:    goto    161
   98:    getstatic    #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   101:    ldc    #6; //String 3
   103:    invokevirtual    #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   106:    goto    161
   109:    getstatic    #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   112:    ldc    #7; //String 5
   114:    invokevirtual    #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   117:    goto    161
   120:    getstatic    #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   123:    ldc    #8; //String 10
   125:    invokevirtual    #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   128:    goto    161
   131:    getstatic    #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   134:    ldc    #9; //String 13
   136:    invokevirtual    #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   139:    goto    161
   142:    getstatic    #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   145:    ldc    #10; //String 14
   147:    invokevirtual    #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   150:    goto    161
   153:    getstatic    #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   156:    ldc    #11; //String default
   158:    invokevirtual    #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   161:    return
 
}

从中可以看到tableswitch使用的跳转表。它这样查找,如果case值不在//0 to 14之间,直接执行default,如果在此范围之内,则取目标值-0这一项作为目标,比如switch(i),i为3,则跳转到3-0=3,使用数组中的第三项作为目标,也就是3: 98;直接去执行98行。

如果case中的值比较稀疏,则使用lookupswitch:

public class Test2 {
 
    public static void main(String[] args) {
        int i = 3;
        switch (i) {
            case 3:
                System.out.println("3");
                break;
            case 20:
                System.out.println("20");
                break;
            case 50:
                System.out.println("50");
                break;
            case 100:
                System.out.println("100");
                break;
        }
 
 
    }
}

编译为

public static void main(java.lang.String[]);
  Code:
   0:    iconst_3
   1:    istore_1
   2:    iload_1
   3:    lookupswitch{ //4
        3: 44;
        20: 55;
        50: 66;
        100: 77;
        default: 85 }
   44:    getstatic    #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   47:    ldc    #3; //String 3
   49:    invokevirtual    #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   52:    goto    85
   55:    getstatic    #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   58:    ldc    #5; //String 20
   60:    invokevirtual    #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   63:    goto    85
   66:    getstatic    #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   69:    ldc    #6; //String 50
   71:    invokevirtual    #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   74:    goto    85
   77:    getstatic    #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   80:    ldc    #7; //String 100
   82:    invokevirtual    #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   85:    return

可以看到其中的
 3: lookupswitch{ //4
3: 44;
20: 55;
50: 66;
100: 77;
default: 85 }
这个就要挨着查表确定跳转位置了。

  总结:在第一个例子中可以看出使用switch case的时候在匹配条件的时候是直接跳转的,所以效率相对会比if语句中逐个比较会快。而且还有一点是在switch语句中看不到的,第一个switch case语句中会首先判断case值在不在目标值中,如果不在,直接执行default,而不是逐个去比较,全部不符合条件之后再执行default。

原文出处:http://bbs.csdn.net/topics/300023354

原作者:ZangXT

 

原文地址:https://www.cnblogs.com/sxzwj/p/6046948.html