为什么在 Java 7 中,对于 String 的 switch 语句比 if else 更快?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10836055/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 02:47:21  来源:igfitidea点击:

Why is the switch statement faster than if else for String in Java 7?

javaif-statementswitch-statementjava-7

提问by user1428716

In Java 7a stringobject can be in the expression of a switchstatement. Can someone explain the below statement from official documentation?

Java 7 中string对象可以在switch语句的表达式中。有人可以从官方文档中解释以下声明吗?

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

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

回答by Paul Vargas

Java Code

Java代码

Having two versions of a class, e.g.

有两个版本的类,例如

With if-then-else:

if-then-else

public class IfThenElseClass {
    public static void main(String[] args) {
        String str = "C";
        if ("A".equals(str)) {

        } else if ("B".equals(str)) {

        } else if ("C".equals(str)) {

        }
    }
}

With switch:

switch

public class SwitchClass {
    public static void main(String[] args) {
        String str = "C";
        switch (str) {
            case "A":
                break;
            case "B":
                break;
            case "C":
                break;
        }
    }
}

Bytecode

字节码

Let's take a look at the bytecode. Getting the bytecode for if-then-elseversion:

我们来看看字节码。获取if-then-else版本的字节码:

Compiled from "CompileSwitch.java"
public class CompileSwitch {
  public CompileSwitch();
    Code:
       0: aload_0
       1: invokespecial #8  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #16 // String C
       2: astore_1
       3: ldc           #18 // String A
       5: aload_1
       6: invokevirtual #20 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
       9: ifne          28
      12: ldc           #26 // String B
      14: aload_1
      15: invokevirtual #20 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
      18: ifne          28
      21: ldc           #16 // String C
      23: aload_1
      24: invokevirtual #20 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
      27: pop
      28: return
}

Getting the bytecode for switchversion:

获取switch版本的字节码:

Compiled from "CompileSwitch.java"
public class CompileSwitch {
  public CompileSwitch();
    Code:
       0: aload_0
       1: invokespecial #8 // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #16 // String C
       2: astore_1
       3: aload_1
       4: dup
       5: astore_2
       6: invokevirtual #18 // Method java/lang/String.hashCode:()I
       9: lookupswitch  { // 3
                    65: 44
                    66: 56
                    67: 68
               default: 77
          }
      44: aload_2
      45: ldc           #24 // String A
      47: invokevirtual #26 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
      50: ifne          77
      53: goto          77
      56: aload_2
      57: ldc           #30 // String B
      59: invokevirtual #26 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
      62: ifne          77
      65: goto          77
      68: aload_2
      69: ldc           #16 // String C
      71: invokevirtual #26 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
      74: ifne          77
      77: return
}

Conclusion

结论

  • In the first version compares the string by calling the equalsmethod for each condition, until it is found.

  • In the second version is obtained first hashCodeof the string. Then this is compared with the values ??hashCodeeach case. See the lookupswitch. If any of these values ??is repeated just happens to run the code for the case. Otherwise, call the equalsmethod of the cases tied. This is much faster than ever call the equalsmethod only.

  • 在第一个版本中,通过equals为每个条件调用方法来比较字符串,直到找到为止。

  • 在第二个版本中首先获得hashCode字符串。然后将其与值进行比较??hashCode每个case. 见lookupswitch。如果这些值中的任何一个被重复,则恰好运行case. 否则,调用equals绑定的情况下的方法。这比equals仅调用方法要快得多。

回答by dasblinkenlight

switchon strings can be faster for the same reason why a lookup in a hash set of strings may be faster than a lookup in a list of strings: you can do a lookup in O(1)rather than in O(N), where Nis the number of strings.

switch在字符串中查找可能比在字符串列表中查找更快的原因相同:您可以在 inO(1)而不是 in 中进行查找O(N),其中N是字符串的数量。

Recall that switchis more efficient than a chain of if-then-elsestatements because it is a calculated jump: an offset in code is calculated based on the value, and then the jump to that offset is executed. Java can pull a similar trick on strings using the mechanism similar to that employed in hash maps and hash sets.

回想一下,这switchif-then-else语句链更有效,因为它是计算跳转:代码中的偏移量是根据值计算的,然后执行到该偏移量的跳转。Java 可以使用类似于散列映射和散列集合中使用的机制在字符串上使用类似的技巧。

回答by javatutorial

It's more efficient something like:

它更有效,例如:

switch(yourString) {
    case "text1":
        // your code
        break;
    case "text2":
        // etc.
}

than the correspondent:

比记者:

if (yourString.equals("text1")) {
     // your code
} else if (yourString.equals("text2")) {
     // etc.
}

回答by tagtraeumer

i guess what it means, or what i understand is that the bytecode (when you compile your java class) that created from an switch statement using string is faster and more efficient than the bytecode that is created from an if-else statement using string. both can do the same job, bit switch is apparently more efficient.

我猜这意味着什么,或者我理解的是,从使用字符串的 switch 语句创建的字节码(当您编译 java 类时)比使用字符串从 if-else 语句创建的字节码更快、更有效。两者都可以做同样的工作,位切换显然更有效。

switch (str) {
            case "A":  
                     // do something
                     break;
            case "B":
                     // do something
                     break;
            default: 
                     //do something
                     break;
}

is better than

if(str.equals("A")) {
//do something
} else if(str-equals("B")) {
//do something
} else {
//do something
}