为什么说在使用多条件判断时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