【问题标题】:Why is the switch statement faster than if else for String in Java 7?为什么 Java 7 中的 switch 语句比 String 的 if else 更快?
【发布时间】:2012-05-31 14:55:46
【问题描述】:

Java 7 中,string 对象可以在 switch 语句的表达式中。有人可以解释official documentation的以下声明吗?

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

【问题讨论】:

  • 当然。它转化为:如果你在一大组 if-than-else 语句中比较字符串,你应该使用 switch 来代替
  • 语句的哪一部分不明白?
  • 非字符串特定版本:stackoverflow.com/questions/2086529/…

标签: java if-statement switch-statement java-7


【解决方案1】:

Java 代码

有两个版本的类,例如

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)) {

        }
    }
}

switch:

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

字节码

让我们看一下字节码。获取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
}

获取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
}

结论

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

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

【讨论】:

  • 这是我一直在寻找的答案。谢谢保罗
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

    这样更有效:

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

    比记者:

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

    【讨论】:

      【解决方案4】:

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

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

      优于

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-04-02
        • 1970-01-01
        • 1970-01-01
        • 2013-12-02
        • 2010-10-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多