J'ai toujours l'habitude d'utiliser l'instruction if, else-if au lieu de plusieurs instructions if.
Exemple:
int val = -1;
if (a == b1) {
return c1;
} else if (a == b2) {
return c2;
} ...
...
} else {
return c11;
}
Comment se compare-t-il à l'exemple 2:
if (a == b1) {
return c1;
}
if (a == b2) {
return c2;
}
....
if (a == b11) {
return c11;
}
Je sais que les fonctionnalités sont les mêmes. Mais est-il préférable de faire si sinon, si non? Cela a été soulevé par un de mes amis lorsque j'ai souligné qu'il pouvait structurer la base de code différemment pour la rendre plus propre. C'est déjà une habitude pour moi depuis longtemps mais je n'ai jamais demandé pourquoi.
Les instructions if-elseif-else
Cessent de faire des comparaisons dès qu'elles en trouvent une qui est vraie. if-if-if
Fait chaque comparaison. Le premier est plus efficace.
Edit: Il a été souligné dans les commentaires que vous faites un return
dans chaque bloc if
. Dans ces cas, ou dans les cas où le contrôle quittera la méthode (exceptions), il n'y a pas de différence entre faire plusieurs instructions if
et faire des instructions if-elseif-else
.
Cependant, il est préférable d'utiliser de toute façon if-elseif-else
. Supposons que vous modifiez votre code de manière à ne pas faire de return
dans chaque bloc de if
. Ensuite, pour rester efficace, vous devez également passer à un idiome if-elseif-else
. Le faire être if-elseif-else
Dès le début vous évite des modifications à l'avenir, et est plus clair pour les personnes qui lisent votre code (soyez témoin de la mauvaise interprétation que je viens de vous donner en faisant un survol de votre code!).
Qu'en est-il du cas où b1 == b2
? (Et si a == b1
et a == b2
?)
Lorsque cela se produit, de manière générale, les deux morceaux de code suivants peuvent avoir un comportement différent:
if (a == b1) {
/* do stuff here, and break out of the test */
}
else if (a == b2) {
/* this block is never reached */
}
et:
if (a == b1) {
/* do stuff here */
}
if (a == b2) {
/* do this stuff, as well */
}
Si vous souhaitez délimiter clairement les fonctionnalités des différents cas, utilisez if-else
ou switch-case
pour faire n test.
Si vous souhaitez des fonctionnalités différentes pour plusieurs cas, utilisez plusieurs blocs if
comme tests séparés.
Il ne s'agit pas de "meilleures pratiques" mais de définir si vous avez un ou plusieurs tests.
Ils ne sont PAS fonctionnellement équivalents.
La seule façon dont il serait fonctionnellement équivalent est que vous fassiez une instruction "if" pour chaque valeur possible d'un (c'est-à-dire: chaque valeur éventuellement int, telle que définie dans limits.h en C; en utilisant INT_MIN et INT_MAX, ou l'équivalent en Java ).
L'instruction else vous permet de couvrir toutes les valeurs restantes possibles sans avoir à écrire des millions d'instructions "si".
En outre, il est préférable d'utiliser le codage si ... sinon si ... sinon, tout comme dans une instruction switch/case, votre compilateur vous lancera un avertissement si vous ne fournissez pas de déclaration de cas "par défaut". Cela vous empêche d'ignorer les valeurs non valides dans votre programme. par exemple:
double square_root(double x) {
if(x > 0.0f) {
return sqrt(x);
} else if(x == 0.0f) {
return x;
} else {
printf("INVALID VALUE: x must be greater than zero");
return 0.0f;
}
}
Voulez-vous taper des millions d'instructions if pour chaque valeur possible de x dans ce cas? J'en doute :)
À votre santé!
return
dans chaque branche if
.Dans votre code, vous avez des instructions return
dans chacune des conditions if. Lorsque vous avez une situation comme celle-ci, il y a deux façons d'écrire cela. Le premier est de savoir comment vous l'avez écrit dans l'exemple 1:
if (a == b1) {
return c1;
} else if (a == b2) {
return c2;
} else {
return c11;
}
L'autre est le suivant:
if (a == b1) {
return c1;
}
if (a == b2) {
return c2;
}
return c11; // no if or else around this return statement
Ces deux façons d'écrire votre code sont identiques.
La façon dont vous avez écrit votre code dans l'exemple 2 ne se compilerait pas en C++ ou Java (et serait un comportement indéfini en C), car le compilateur ne sait pas que vous avez couvert tous les possibles valeurs de a
donc il pense qu'il y a un chemin de code à travers la fonction qui peut vous mener à la fin de la fonction sans retourner de valeur de retour.
if (a == b1) {
return c1;
}
if (a == b2) {
return c2;
}
...
if (a == b11) {
return c11;
}
// what if you set a to some value c12?
return
dans chaque branche if
.Sans les instructions return
dans chaque branche if
, votre code ne serait fonctionnellement identique que si les instructions suivantes sont vraies:
a
dans aucune des branches if
.==
est une relation d'équivalence (au sens mathématique) et aucune des b1
à b11
sont dans la même classe d'équivalence.==
n'a pas d'effets secondaires.Pour clarifier davantage le point # 2 (et aussi le point # 3):
==
est toujours une relation d'équivalence en C ou Java et n'a jamais d'effets secondaires.==
, comme C++, Ruby ou Scala, le ==
L'opérateur peut ne pas être une relation d'équivalence et il peut avoir des effets secondaires. Nous espérons certainement que quiconque supplantera le ==
L'opérateur était suffisamment sain d'esprit pour écrire une relation d'équivalence qui n'a pas d'effets secondaires, mais il n'y a aucune garantie.==
n'est ni transitif, ni symétrique. (En Javascript, ===
est une relation d'équivalence.)En termes de performances, l'exemple n ° 1 est garanti de ne pas effectuer de comparaisons après celui qui correspond. Il peut être possible pour le compilateur d'optimiser # 2 pour ignorer les comparaisons supplémentaires, mais c'est peu probable. Dans l'exemple suivant, ce n'est probablement pas le cas, et si les chaînes sont longues, les comparaisons supplémentaires ne sont pas bon marché.
if (strcmp(str, "b1") == 0) {
...
}
if (strcmp(str, "b2") == 0) {
...
}
if (strcmp(str, "b3") == 0) {
...
}
Cela dépend totalement de la condition que vous testez. Dans votre exemple, cela ne fera finalement aucune différence, mais comme meilleure pratique, si vous souhaitez que l'une des conditions soit finalement exécutée, vous feriez mieux de l'utiliser sinon
if (x > 1) {
System.out.println("Hello!");
}else if (x < 1) {
System.out.println("Bye!");
}
Notez également que si la première condition est VRAIE, la seconde ne sera PAS vérifiée du tout, mais si vous utilisez
if (x > 1) {
System.out.println("Hello!");
}
if (x < 1) {
System.out.println("Bye!");
}
La deuxième condition sera vérifiée même si la première condition est VRAIE. L'optimiseur pourrait éventuellement résoudre ce problème, mais pour autant que je sache, il se comporte de cette façon. De plus, le premier est celui qui est destiné à être écrit et se comporte comme ceci, donc c'est toujours le meilleur choix pour moi, sauf si la logique l'exige autrement.
Dans la plupart des cas, l'utilisation d'instructions if-elseif-else et switch sur des instructions if-if-if est plus efficace (car elle facilite la création de tables de saut/recherche par le compilateur) et de meilleures pratiques car elle rend votre code plus lisible, De plus, le compilateur s'assure que vous incluez un cas par défaut dans le commutateur. Cette réponse, ainsi que cette tablea comparant les trois déclarations différentes ont été synthétisées en utilisant d'autres messages de réponse sur cette page ainsi que ceux d'un similaire SO question .
J'ai tendance à penser que l'utilisation de else if
est plus facile et plus robuste face aux changements de code. Si quelqu'un devait ajuster le flux de contrôle de la fonction et remplacer un retour avec effet secondaire ou un appel de fonction par un try-catch
les else-if
échouerait dur si toutes les conditions étaient vraiment exclusives. Cela dépend vraiment beaucoup du code exact avec lequel vous travaillez pour porter un jugement général et vous devez considérer les compromis possibles avec brièveté.
Je préfère les structures if/else, car il est beaucoup plus facile d'évaluer tous les états possibles de votre problème dans chaque variation avec des commutateurs. C'est plus robuste que je trouve et plus rapide à déboguer, surtout lorsque vous effectuez plusieurs évaluations booléennes dans un environnement de type faible comme PHP, par exemple pourquoi elseif est mauvais (exagéré pour la démonstration):
if(a && (c == d))
{
} elseif ( b && (!d || a))
{
} elseif ( d == a && ( b^2 > c))
{
} else {
}
Ce problème a au-delà de 4 ^ 2 = 16 états booléens, ce qui est simplement pour démontrer les effets de typage faible qui aggravent les choses. Il n'est pas si difficile d'imaginer une variable à trois états, un problème à trois variables impliqué dans un if ab elseif bc
type de chemin.
Laissez l'optimisation au compilateur.
if
et else if
est différent de deux instructions if
consécutives. Dans le premier, lorsque le CPU prend la première branche if
la else if
ne sera pas vérifié. Dans les deux instructions if
consécutives, même si la première if
est vérifiée et prise, la if
suivante sera également vérifiée et prise si la condition est vraie.
Je pense que ces extraits de code sont équivalents pour la simple raison que vous avez de nombreuses instructions return
. Si vous aviez une seule instruction return
, vous utiliseriez des constructions else
qui ici ne sont pas nécessaires.
Votre comparaison repose sur le fait que le corps des instructions if renvoie le contrôle de la méthode. Sinon, la fonctionnalité serait différente.
Dans ce cas, ils exécutent la même fonctionnalité. Ce dernier est beaucoup plus facile à lire et à comprendre à mon avis et serait mon choix quant à l'utilisation.
Ils font potentiellement des choses différentes.
Si a
est égal à b1
et b2
, vous entrez deux blocs if
. Dans le premier exemple, vous n'en saisissez qu'un seul. J'imagine que le premier exemple est plus rapide car le compilateur doit probablement vérifier chaque condition séquentiellement car certaines règles de comparaison peuvent s'appliquer à l'objet. Il peut être en mesure de les optimiser ... mais si vous ne voulez en saisir qu'une, la première approche est plus évidente, moins susceptible de conduire à une erreur de développeur ou à un code inefficace, donc je recommanderais certainement cela.
La réponse de CanSpice est correcte. Une considération supplémentaire pour les performances consiste à déterminer quel conditionnel se produit le plus souvent. Par exemple, si a == b1 ne se produit que 1% du temps, vous obtenez de meilleures performances en vérifiant d'abord l'autre cas.
La réponse de Gir Loves Tacos est également bonne. La meilleure pratique consiste à vous assurer que tous les cas sont couverts.