web-dev-qa-db-fra.com

Comment la chaîne dans l'instruction switch est-elle plus efficace que l'instruction if-else correspondante?

documentation Java dit

Le compilateur Java génère généralement un bytecode plus efficace à partir des instructions switch qui utilisent des objets String que des instructions if-then-else chaînées.

AFAIK, même String dans le commutateur utilise .equals() en interne de manière sensible à la casse. Alors, quelle efficacité signifient-ils dans ce contexte? Compilation plus rapide? Moins de bytecodes? meilleure performance?

59
Aniket Thakur

L'utilisation d'une instruction switch est plus rapide qu'égal (mais seulement de façon notable lorsqu'il y a plus que quelques chaînes) car elle utilise d'abord le hashCode de la chaîne sur laquelle switch pour déterminer le sous-ensemble du chaînes qui pourraient éventuellement correspondre. Si plusieurs chaînes dans les étiquettes de cas ont le même hashCode, la JVM effectuera des appels séquentiels à equals et même s'il n'y a qu'une seule chaîne dans les étiquettes de cas qu'un hashCode, la JVM doit appeler equals pour confirmer que la chaîne de l'étiquette de cas est vraiment égale à celle de l'expression de commutation.

Les performances d'exécution d'un commutateur sur des objets String sont comparables à une recherche dans un HashMap.

Ce morceau de 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;
    }
}

Est compilé en interne et exécuté comme ce morceau de code:

(pas littéralement, mais si vous décompilez les deux morceaux de code, vous voyez que la même séquence d'actions se produit)

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;
    }
}
72
Erwin Bolwidt

Dans general, les instructions switch sont meilleures car elles sont (en gros) O(1), tandis qu'une chaîne de if-else Est O(n)

Le fait d'avoir des conditions n peut entraîner jusqu'à n comparaisons à l'aide d'une instruction chaînée if-else.

Une instruction switch peut "sauter" directement à la condition appropriée (comme une carte) ou au cas par défaut, ce qui en fait O(1).

19
Tyler

Ceci est un fragment de bytecode généré à partir d'un exemple dans les documents:

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

l'utilisation de LOOKUPSWITCH est plus performante que la logique if-else

7
Evgeniy Dorofeev