switch 语句中的 String 如何比相应的 if-else 语句更有效?
Posted
技术标签:
【中文标题】switch 语句中的 String 如何比相应的 if-else 语句更有效?【英文标题】:How is String in switch statement more efficient than corresponding if-else statement? 【发布时间】:2014-04-02 08:56:54 【问题描述】:Java documentation 说
Java 编译器从使用 String 对象的 switch 语句生成的字节码通常比从链式 if-then-else 语句生成的字节码更有效。
AFAIK 甚至 String in switch 在内部以区分大小写的方式使用.equals()
。那么在这种情况下,它们意味着什么效率。编译速度更快?更少的字节码?性能更好?
【问题讨论】:
帮助链接:blackwasp.co.uk/SpeedTestIfElseSwitch.aspx 顺便说一句,向所有人道歉;我显然是在昨晚睡着的时候写的,只是没有连接到基于散列的调度表。是的,这很有意义,不仅适用于非整数值,而且适用于宽间距的稀疏值。 “注意:为避免名誉受损,请先动脑筋再动手。” 【参考方案1】:使用 switch 语句比 equals 更快(但仅在有多个字符串时才明显),因为它首先使用switch
所在字符串的hashCode
来确定可以可能匹配。如果case标签中有多个字符串具有相同的hashCode,JVM会依次调用equals
,即使case标签中只有一个字符串是hashCode,JVM也需要调用equals
来确认case 标签中的字符串确实等于 switch 表达式中的字符串。
在 String 对象上切换的运行时性能与在 HashMap
中的查找相当。
这段代码:
public static void main(String[] args)
String s = "Bar";
switch (s)
case "Foo":
System.out.println("Foo match");
break;
case "Bar":
System.out.println("Bar match");
break;
内部编译并执行如下代码:
(不是字面意思,但如果你反编译两段代码,你会发现发生了完全相同的动作序列)
final static int FOO_HASHCODE = 70822; // "Foo".hashCode();
final static int BAR_HASHCODE = 66547; // "Bar".hashCode();
public static void main(String[] args)
String s = "Bar";
switch (s.hashCode())
case FOO_HASHCODE:
if (s.equals("Foo"))
System.out.println("Foo match");
break;
case BAR_HASHCODE:
if (s.equals("Bar"))
System.out.println("Bar match");
break;
【讨论】:
他们也可以使用 trie 实现 更多关于内部编译的细节在这里:docs.oracle.com/javase/specs/jvms/se7/html/…【参考方案2】:在一般中,switch 语句更好,因为它们(粗略地说)是O(1)
,而if-else
的链是O(n)
拥有n
条件可能会导致使用链式if-else
语句进行最多n
比较。
switch 语句可以直接“跳转”到适当的条件(如地图)或默认情况,使其成为O(1)
。
【讨论】:
根据@Erwin Bolwidt 提供的解释,这是有道理的。【参考方案3】:这是从文档中的示例生成的字节码片段:
INVOKEVIRTUAL java/lang/String.hashCode ()I
LOOKUPSWITCH
-2049557543: L2
-1984635600: L3
-1807319568: L4
与 if-else 逻辑相比,使用 LOOKUPSWITCH 具有更好的性能
【讨论】:
LOOKUPSWITCH 是一直存在的字节码指令。当它打开的整数值相距很远时,使用它代替 TABLESWITCH。正如您在程序集中看到的,它不会打开字符串本身,而是打开字符串的 hashCode。您还需要在 L2、L3 或 L4 显示字节码:您会看到需要调用 String.equals 来验证字符串是否真的相同。 @ErwinBolwidt 但有趣的是,TABLESWITCH 不一定是它听起来的样子:在默认设置下,在 17 种情况下,它在汇编中被转换为 cmp/je 序列(即 if/goto)。拥有18个或更多的案例,它也成为了组装级别的真正的表开关。 有趣。还注意到(至少)Eclipse 编译器不会发出 TABLESWITCH,即使您打开带有连续哈希码(“A”、“B”、“C”等)的字符串。以上是关于switch 语句中的 String 如何比相应的 if-else 语句更有效?的主要内容,如果未能解决你的问题,请参考以下文章
Java中String,long,byte类型可以作为switch中的表达式吗?
[UE4]Switch on String,根据字符串决定条件分支,类似于高级语言中的switch语句
java编写程序:输入一个学生的成绩,给出相应的等,(用switch语句实现:0-59:D 60-69:C 70-84:B 85-100:A