switch语句中的String如何比相应的if-else语句更有效?

时间:2022-09-02 14:56:26

Java documentation says

Java文档说

The Java compiler generates generally more efficient bytecode from switch statements that use String objects than from chained if-then-else statements.

Java编译器通常使用String对象生成比使用链式if-then-else语句更高效的字节码。

AFAIK even String in switch uses .equals() internally in a case sensitive manner. So what efficiency do they mean in this context. Faster compilation? Less bytecodes ? better performance?

AFAIK even String in switch在内部以区分大小写的方式使用.equals()。那么它们在这种背景下的效率是多少。编译速度更快?字节码少?更好的性能?

3 个解决方案

#1


60  

Using a switch statement is faster than equals (but only noticeably when there are more than just a few strings) because it first uses the hashCode of the string that switch on to determine the subset of the strings that could possibly match. If more than one string in the case labels has the same hashCode, the JVM will perform sequential calls to equals and even if there is only one string in the case labels that a hashCode, the JVM needs to call equals to confirm that the string in the case label is really equal to the one in the switch expression.

使用switch语句比equals更快(但只有当不止一些字符串时才会显着),因为它首先使用打开的字符串的hashCode来确定可能匹配的字符串子集。如果case标签中的多个字符串具有相同的hashCode,则JVM将执行对equals的顺序调用,即使在case标签中只有一个字符串表示hashCode,JVM需要调用equals以确认该字符串为case标签实际上等于switch表达式中的标签。

The runtime performance of a switch on String objects is comparable to a lookup in a HashMap.

String对象上的开关的运行时性能与HashMap中的查找相当。

This piece of code:

这段代码:

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;
    }
}

Is internally compiled to and executed like this piece of code:

内部编译并执行像这段代码:

(not literally, but if you decompile both pieces of code you see that the exact same sequence of actions occurs)

(不是字面意思,但是如果你反编译两段代码,你就会看到完全相同的动作序列发生)

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;
    }
}

#2


17  

In general, switch statements are better because they are (loosely speaking) O(1), while a chain of if-else is O(n)

一般来说,switch语句更好,因为它们(松散地说)是O(1),而if-else链是O(n)

Having n conditions could result in up to n comparisons using a chained if-else statements.

具有n个条件可能导致使用链式if-else语句进行多达n次比较。

A switch statement can "jump" directly to the appropriate condition (like a map) or to the default case, making it O(1).

switch语句可以直接“跳转”到适当的条件(如地图)或默认情况下,使其成为O(1)。

#3


6  

This is a bytecode fragment generated from example in the docs:

这是从docs中的示例生成的字节码片段:

 INVOKEVIRTUAL java/lang/String.hashCode ()I
    LOOKUPSWITCH
      -2049557543: L2
      -1984635600: L3
      -1807319568: L4

using LOOKUPSWITCH has better perfomance compared to if-else logic

与if-else逻辑相比,使用LOOKUPSWITCH具有更好的性能

#1


60  

Using a switch statement is faster than equals (but only noticeably when there are more than just a few strings) because it first uses the hashCode of the string that switch on to determine the subset of the strings that could possibly match. If more than one string in the case labels has the same hashCode, the JVM will perform sequential calls to equals and even if there is only one string in the case labels that a hashCode, the JVM needs to call equals to confirm that the string in the case label is really equal to the one in the switch expression.

使用switch语句比equals更快(但只有当不止一些字符串时才会显着),因为它首先使用打开的字符串的hashCode来确定可能匹配的字符串子集。如果case标签中的多个字符串具有相同的hashCode,则JVM将执行对equals的顺序调用,即使在case标签中只有一个字符串表示hashCode,JVM需要调用equals以确认该字符串为case标签实际上等于switch表达式中的标签。

The runtime performance of a switch on String objects is comparable to a lookup in a HashMap.

String对象上的开关的运行时性能与HashMap中的查找相当。

This piece of code:

这段代码:

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;
    }
}

Is internally compiled to and executed like this piece of code:

内部编译并执行像这段代码:

(not literally, but if you decompile both pieces of code you see that the exact same sequence of actions occurs)

(不是字面意思,但是如果你反编译两段代码,你就会看到完全相同的动作序列发生)

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;
    }
}

#2


17  

In general, switch statements are better because they are (loosely speaking) O(1), while a chain of if-else is O(n)

一般来说,switch语句更好,因为它们(松散地说)是O(1),而if-else链是O(n)

Having n conditions could result in up to n comparisons using a chained if-else statements.

具有n个条件可能导致使用链式if-else语句进行多达n次比较。

A switch statement can "jump" directly to the appropriate condition (like a map) or to the default case, making it O(1).

switch语句可以直接“跳转”到适当的条件(如地图)或默认情况下,使其成为O(1)。

#3


6  

This is a bytecode fragment generated from example in the docs:

这是从docs中的示例生成的字节码片段:

 INVOKEVIRTUAL java/lang/String.hashCode ()I
    LOOKUPSWITCH
      -2049557543: L2
      -1984635600: L3
      -1807319568: L4

using LOOKUPSWITCH has better perfomance compared to if-else logic

与if-else逻辑相比,使用LOOKUPSWITCH具有更好的性能