Почему оператор switch быстрее, чем if else для String в Java 7?

В Java 7 объект string может находиться в выражении оператора switch. Может ли кто-нибудь объяснить приведенное ниже выражение официальная документация?

Компилятор Java генерирует в целом более эффективный байт-код из операторов switch, которые используют Объекты String, чем из прикованных операторов if-then-else.

Ответы

Ответ 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;
        }
    }
}

Bytecode

Посмотрим на байт-код. Получение байт-кода для версии 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), а не в O(N) > , где N - количество строк.

Напомним, что switch более эффективен, чем цепочка операторов if-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

Я думаю, что это значит или я понимаю, что байт-код (когда вы компилируете свой класс java), созданный из оператора switch с использованием строки, быстрее и эффективнее, чем байт-код, созданный из оператора 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
}