Duplicata possible:
Dois-je utiliser des instructions switch ou long si… sinon des chaînes?
Je travaille sur un petit programme qui effectuera un tri par insertion. Un nombre sera entré via le clavier et stocké dans une variable que j'ai appelée "num". J'ai décidé d'utiliser une instruction switch afin d'obtenir le nombre entré.
switch( e.getKeyCode() ) {
case KeyEvent.VK_0: num = 0; break;
case KeyEvent.VK_1: num = 1; break;
case KeyEvent.VK_2: num = 2; break;
case KeyEvent.VK_3: num = 3; break;
case KeyEvent.VK_4: num = 4; break;
case KeyEvent.VK_5: num = 5; break;
case KeyEvent.VK_6: num = 6; break;
case KeyEvent.VK_7: num = 7; break;
case KeyEvent.VK_8: num = 8; break;
case KeyEvent.VK_9: num = 9; break;
}
J'ai réalisé qu'un autre plan d'action aurait pu être d'utiliser un ensemble d'instructions if.
if( e.getKeyCode() == KeyEvent.VK_0 )
num = 0;
else if( e.getKeyCode() == KeyEvent.VK_1 )
num = 1;
etc. for every number up until 9.
Je me suis alors demandé quelle était la différence essentielle entre une instruction switch et une série d'instructions if. Je sais que cela économise de l'espace et du temps pour écrire, mais ce n'est pas tant que ça. Donc, ma question est, en dehors de l'espace, une instruction switch diffère-t-elle d'une série de déclarations if de quelque manière que ce soit? Est-ce plus rapide, moins sujet aux erreurs, etc.?
Cette question n'affecte vraiment pas beaucoup mon code. Je me demandais juste. En outre, cette question concerne le Java, pas tout autre langage de programmation.
Vous avez raison, ils sont identiques sur le plan fonctionnel. Mais en pratique, pourquoi taper (ou couper et coller) tout cela quand une instruction switch
est tellement plus concise?
La différence n'est pas celle de fonctionnalité, mais de intention. Lorsque vous écrivez une instruction switch
, vous dites en fait au lecteur que cette section de code peut se ramifier de plusieurs manières en fonction de l'état de ne seule variable. Cette instruction est appliquée par le compilateur.
Cependant, lorsque vous écrivez un bloc if
, vous n'indiquez pas délibérément qu'une seule variable est impliquée. Lorsque vous écrivez une série de if
, comme vous le suggérez, il est beaucoup plus difficile de voir que la ramification n'est basée que sur une seule variable. Il s'agit d'un problème de maintenance. Les développeurs qui doivent modifier votre code à l'avenir peuvent ne pas réaliser que vous vouliez que cette décision soit si ciblée et commenceront à ajouter des conditions qui n'utilisent pas cette variable. Quelqu'un viendra et dira: "Je veux que num soit égal à 10 si la dernière séquence de touches était 5-4-8", et claquera un else if
à la fin de votre bloc. Finalement, cette section deviendra un nœud gourdien de if...else if
des conditions que personne ne peut comprendre. L'avenir vous détestera et le mauvais karma sera ajouté à votre compte.
Utilisez une instruction switch
lorsque cela est possible. Il indique clairement que cette section de code repose sur une seule variable et est beaucoup plus évolutive.
La puissance de switch
est double:
Votre post commente déjà la descriptivité de switch
par rapport à une chaîne de if
s, donc je vais me concentrer sur la partie 2.
Si le nombre d'étiquettes de commutateur est N
, une chaîne de if
s prend O(N)
à distribuer, tandis qu'un switch
distribue toujours dans O(1)
. Voici comment procéder: le compilateur place les adresses des étiquettes de commutateur dans un tableau, calcule un index en fonction des valeurs d'étiquette et effectue un saut directement, sans comparer l'expression de commutateur à la valeur une par une. Dans le cas de chaînes utilisées comme étiquettes de commutateur, le compilateur produit une table de hachage, qui recherche également une adresse dans O(1)
.
Lorsque le nombre de commutateurs devient élevé (supérieur à 100), la conversion entre switch
et une chaîne de if
s ne peut plus être considérée comme une micro-optimisation: le gain de temps peut être très important, notamment dans boucles serrées. Si un profileur vous dit que votre chaîne de if
s prend beaucoup de temps, la réécriture en tant que switch
peut très bien être une solution.
Certaines personnes pensent que le changement de lecture se fait plus facilement que si sinon. Mais je suis d'accord avec la conviction que le souci de la performance relève de la micro-optimisation.
SO Java de ce Q
SO Java de ce Q v2
version SO C++ de ce Q
version SO C++ de ce Q v2
version SO C # ...
Un switch
peut être plus efficace qu'une série de if
/else if
déclarations. Voir cet article pour un exemple en C. La grande différence est qu'avec les instructions if
, la condition pour chaque cas peut être n'importe quoi. Par exemple, vous pouvez écrire du code équivalent à:
If it's raining, put on a jacket, otherwise if it's a Sunday, call your mother.
Avec un switch
, cependant, chaque comparaison va être un test d'équivalence, et la seule chose qui change est la valeur à laquelle vous comparez. Comme le lien l'explique, si les valeurs des cas sont toutes proches les unes des autres, le compilateur peut implémenter le commutateur à l'aide d'une table de saut. Autrement dit, le compilateur peut utiliser la valeur que vous allumez pour calculer directement l'adresse du code pour ce cas. Cela évite la nécessité d'une séquence de comparaisons. Maintenant, un compilateur vraiment intelligent pourrait remarquer que vous utilisez une série d'instructions if
de la même manière et faites la même chose; Je ne sais pas si c'est une optimisation courante ou non.
Cela dit, je ne m'inquiéterais pas trop du code généré par le compilateur. Au lieu de cela, choisissez entre if
et switch
selon ce qui semble naturel pour vous et les autres programmeurs. Un switch
représente le choix d'un cas parmi un certain nombre de cas où chaque cas a une valeur correspondante. C'est un démultiplexeur. Si vous constatez que vous disposez d'une séquence d'instructions if
qui ont toutes la même condition, à l'exception de la valeur que vous comparez, un switch
peut être plus agréable, plus court, plus évident. façon d'exprimer cela.