一、If语句
If() { } If() {} else {} If() {} if() {} if() {} If() {} else if() {} else if() {} else {} |
说明:
1) 可以进行嵌套,或者多重嵌套,但为保证代码逻辑清晰,提高可读性,尽量不要嵌套。
2) 按先后顺序依次判断是否成立,当一个if 语句检测为真,后面的else if 及 else语句都将被跳过。
在多分支条件下,若最多只有一个分支条件成立,使用If() {} else if() {} else if() {} else {} ,且按分支出现概率从大到小排放条件表达式,即概率上出现最多的放在最前面,减少程序判断次数,提高效率。
多分支同时成立且都需要处理的情况下,需使用If() {} if() {} if() {}。
二、Switch语句
switch(expression){ case value : //语句 break; //可选 case value : //语句 break; //可选 //你可以有任意数量的case语句 default : //可选 //语句 } |
说明:
1) switch 语句中的变量类型可以是: byte、short、int 或者 char。String(从Java SE 7 开始),同时case 标签必须为字符串常量或字面量。
2) switch 语句可以拥有多个 case 语句。每个 case 后面跟一个要比较的值和冒号。
3) case 语句中的值的数据类型必须与变量的数据类型相同,而且只能是常量或者字面常量。
4) 当变量的值与 case 语句的值相等时, case 语句之后的语句开始执行,直到 break 语句出现才会跳出 switch 语句。如果没有 break 语句出现,程序会继续执行下一条 case 语句,直到出现 break 语句。
5) switch 语句可以包含一个 default 分支,该分支必须是switch 语句的最后一个分支。default 在没有case 语句的值和变量值相等的时候执行。default 分支不需要 break 语句。
三、if与switch区别
if...else顺序判断条件分支,遇到表达式值为真时,执行代码,而switch...case生成一个跳转表来指示实际的case分支的地址,跳转表的索引号与switch变量的值相等,通过对应索引号的表项从而到达定位分支的目的。若switch变量为String类型,会有两个跳转表,先将String类型对应为一个int类型,再通过该int类型跳转到对应的分支。
四、if 与switch比较
A) 时间
效率--仅从跳转次数来比较两者的效率, 不考虑编译器的优化和条件传送
分支较多时,大于3,switch效率高。
分支较少时,小于3,if...else结构更好
B)空间
switch...case占用较多的代码空间,因为它要生成跳表。
(特别是当case常量分布范围很大但实际有效值又比较少的情况,switch...case的空间利用率将变得较低。----未能深入理解)
C)适用范围
.switch...case只能处理case为常量(byte、short、int 或者 char。String(从Java SE 7 开始))的情况,对非常量的情况是无能为力的。例如 if (a > 1 && a < 100),是无法使用switch...case来处理的。所以,switch只能是在常量选择分支时比ifelse效率高,但是if else能应用于更多的场合,比较灵活。
五、Java中源码与字节码
从字节码中可以看出switch中存在跳转表 ,类型为String时存在lookupswitch 和tableswitch两张,而为Int类型时只有lookupswitch, Goto语句对应的行号 , 跳转表内 冒号后也为行号 .
1、if else
@Test
public void ifElseTest(int a) {
if (a > 5) {
System.out.println("a值 >5 ----");
} else if (a > 10) {
System.out.println("a值 >10 ----");
} else if (a > 15) {
System.out.println("a值 >15 ----");
}
}
字节码:
public ifElseTest(I)V
@Lorg/junit/Test;()
L0
LINENUMBER 15 L0
ILOAD 1
ICONST_5
IF_ICMPLE L1
L2
LINENUMBER 16 L2
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "a\u503c >5 ----"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
GOTO L3
L1
LINENUMBER 17 L1
FRAME SAME
ILOAD 1
BIPUSH 10
IF_ICMPLE L4
L5
LINENUMBER 18 L5
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "a\u503c >10 ----"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
GOTO L3
L4
LINENUMBER 19 L4
FRAME SAME
ILOAD 1
BIPUSH 15
IF_ICMPLE L3
L6
LINENUMBER 20 L6
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "a\u503c >15 ----"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L3
LINENUMBER 22 L3
FRAME SAME
RETURN
L7
LOCALVARIABLE this Lpractice/basics/IfElseTest; L0 L7 0
LOCALVARIABLE a I L0 L7 1
MAXSTACK = 2
MAXLOCALS = 2
2、switch case
变量为Int类型
public void switchCaseIntTest(int str) {
switch (str) {
case 5:
System.out.println("5 ----");
break;
case 10:
System.out.println("10 ----" );
break;
case 15:
System.out.println("15 ----");
break;
default:
System.out.println("int值 ----");
}
System.out.println("intTest ----");
}
Java字节码
public switchCaseIntTest(I)V
@Lorg/junit/Test;()
L0
LINENUMBER 26 L0
ILOAD 1
LOOKUPSWITCH
5: L1
10: L2
15: L3
default: L4
L1
LINENUMBER 28 L1
FRAME SAME
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "5 ----"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L5
LINENUMBER 29 L5
GOTO L6
L2
LINENUMBER 31 L2
FRAME SAME
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "10 ----"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L7
LINENUMBER 32 L7
GOTO L6
L3
LINENUMBER 34 L3
FRAME SAME
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "15 ----"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L8
LINENUMBER 35 L8
GOTO L6
L4
LINENUMBER 37 L4
FRAME SAME
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "int\u503c ----"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L6
LINENUMBER 39 L6
FRAME SAME
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "intTest ----"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L9
LINENUMBER 40 L9
RETURN
L10
LOCALVARIABLE this Lpractice/basics/IfElseTest; L0 L10 0
LOCALVARIABLE str I L0 L10 1
MAXSTACK = 2
MAXLOCALS = 2
变量类型为String
public void switchCaseStrTest(String str) {
switch (str) {
case "a":
System.out.println("a值 ----");
break;
case "b":
System.out.println("b值 ----" );
break;
case "x":
System.out.println("x值 ----");
break;
case "z":
System.out.println("z值 ----");
break;
default:
System.out.println("abxz值 ----");
}
System.out.println("strTest ----");
}
字节码:
public switchCaseStrTest(Ljava/lang/String;)V
@Lorg/junit/Test;()
L0
LINENUMBER 44 L0
ALOAD 1
ASTORE 2
ICONST_M1
ISTORE 3
ALOAD 2
INVOKEVIRTUAL java/lang/String.hashCode ()I
LOOKUPSWITCH
97: L1
98: L2
120: L3
122: L4
default: L5
L1
FRAME APPEND [java/lang/String I]
ALOAD 2
LDC "a"
INVOKEVIRTUAL java/lang/String.equals (Ljava/lang/Object;)Z
IFEQ L5
ICONST_0
ISTORE 3
GOTO L5
L2
FRAME SAME
ALOAD 2
LDC "b"
INVOKEVIRTUAL java/lang/String.equals (Ljava/lang/Object;)Z
IFEQ L5
ICONST_1
ISTORE 3
GOTO L5
L3
FRAME SAME
ALOAD 2
LDC "x"
INVOKEVIRTUAL java/lang/String.equals (Ljava/lang/Object;)Z
IFEQ L5
ICONST_2
ISTORE 3
GOTO L5
L4
FRAME SAME
ALOAD 2
LDC "z"
INVOKEVIRTUAL java/lang/String.equals (Ljava/lang/Object;)Z
IFEQ L5
ICONST_3
ISTORE 3
L5
FRAME SAME
ILOAD 3
TABLESWITCH
0: L6
1: L7
2: L8
3: L9
default: L10
L6
LINENUMBER 46 L6
FRAME SAME
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "a\u503c ----"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L11
LINENUMBER 47 L11
GOTO L12
L7
LINENUMBER 49 L7
FRAME SAME
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "b\u503c ----"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L13
LINENUMBER 50 L13
GOTO L12
L8
LINENUMBER 52 L8
FRAME SAME
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "x\u503c ----"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L14
LINENUMBER 53 L14
GOTO L12
L9
LINENUMBER 55 L9
FRAME SAME
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "z\u503c ----"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L15
LINENUMBER 56 L15
GOTO L12
L10
LINENUMBER 58 L10
FRAME SAME
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "abxz\u503c ----"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L12
LINENUMBER 60 L12
FRAME CHOP 2
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "strTest ----"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L16
LINENUMBER 61 L16
RETURN
L17
LOCALVARIABLE this Lpractice/basics/IfElseTest; L0 L17 0
LOCALVARIABLE str Ljava/lang/String; L0 L17 1
MAXSTACK = 2
MAXLOCALS = 4
参考文章:
https://www.cnblogs.com/ye-ming/articles/7942472.html
https://www.jb51.net/article/118488.htm