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 语句更有效?的主要内容,如果未能解决你的问题,请参考以下文章

选择语句--switch

Java中String,long,byte类型可以作为switch中的表达式吗?

[UE4]Switch on String,根据字符串决定条件分支,类似于高级语言中的switch语句

switch语句

java编写程序:输入一个学生的成绩,给出相应的等,(用switch语句实现:0-59:D 60-69:C 70-84:B 85-100:A

switch语句能否作用在byte,long,string上