Pourquoi changer est plus rapide que si

J’ai trouvé beaucoup de livres dans java en disant que la déclaration de switch est plus rapide que celle de if else. Mais je n’ai pas trouvé d’anthistoire en disant pourquoi changer est plus rapide que si .

Exemple

J’ai une situation que je dois choisir un élément sur deux, je peux utiliser l’un des moyens suivants

switch(item){ case BREAD: //eat Bread break; default: //leave the restaurant } 

ou en utilisant l’énoncé if comme le suivant

 if(item== BREAD){ //eat Bread }else{ //leave the restaurant } 

compte tenu de l’élément et BREAD est la valeur int constante

Dans l’exemple ci-dessus qui est plus rapide en action et pourquoi?

Parce qu’il existe des codes d’octets spéciaux qui permettent une évaluation efficace des instructions de commutation lorsqu’il y a beaucoup de cas.

Si elle est implémentée avec les instructions IF, vous aurez une vérification, un saut à la clause suivante, une vérification, un saut à la clause suivante et ainsi de suite. Avec switch, la JVM charge la valeur à comparer et parcourt la table de valeurs pour trouver une correspondance, ce qui est plus rapide dans la plupart des cas.

Une instruction switch n’est pas toujours plus rapide qu’une instruction if . Elle évolue mieux qu’une longue liste d’instructions if-else car switch peut effectuer une recherche en fonction de toutes les valeurs. Cependant, pour une courte condition, il ne sera pas plus rapide et pourrait être plus lent.

La machine virtuelle Java actuelle possède deux types de codes d’octet de commutation: LookupSwitch et TableSwitch.

Chaque cas dans une instruction switch a un décalage entier, si ces décalages sont contigus (ou la plupart du temps contigus sans grands espaces) (cas 0: cas 1: cas 2, etc.), alors TableSwitch est utilisé.

Si les décalages sont étalés avec des intervalles importants (cas 0: cas 400: cas 93748:, etc.), alors LookupSwitch est utilisé.

La différence, en bref, est que TableSwitch est effectué à temps constant car chaque valeur dans la plage des valeurs possibles se voit atsortingbuer un décalage de code d’octet spécifique. Ainsi, lorsque vous donnez un décalage de 3 à la déclaration, il sait sauter 3 pour trouver la twig correcte.

Le commutateur de recherche utilise une recherche binary pour trouver la twig de code correcte. Cela se passe en heure O (log n), ce qui est toujours bon, mais pas le meilleur.

Pour plus d’informations à ce sujet, voir ici: Différence entre LookupSwitch de JVM et TableSwitch?

Donc, pour quelle méthode est la plus rapide, utilisez cette approche: Si vous avez 3 cas ou plus dont les valeurs sont consécutives ou presque consécutives, utilisez toujours un commutateur.

Si vous avez 2 cas, utilisez une instruction if.

Pour toute autre situation, le changement est probablement plus rapide, mais ce n’est pas garanti, car la recherche binary dans LookupSwitch pourrait être un mauvais scénario.

De plus, gardez à l’esprit que la JVM exécutera des optimisations JIT sur les instructions if qui tenteront de placer la première twig la plus chaude dans le code. Cela s’appelle “Branch Prediction”. Pour plus d’informations à ce sujet, voir ici: https://dzone.com/articles/branch-prediction-in-java

Vos expériences peuvent varier. Je ne sais pas que la JVM n’utilise pas une optimisation similaire sur LookupSwitch, mais j’ai appris à faire confiance aux optimisations JIT et à ne pas essayer de déjouer le compilateur.

Au niveau du bytecode, la variable sujet est chargée une seule fois dans le registre du processeur à partir d’une adresse mémoire dans le fichier .class structuré chargé par Runtime, et cela se trouve dans une instruction switch; alors que dans une instruction if, une instruction jvm différente est produite par votre DE de compilation de code, et cela nécessite que chaque variable soit chargée dans des registres bien que la même variable soit utilisée dans l’instruction if précédente. Si vous connaissez le codage en langage d’assemblage, ce serait banal; Bien que les coxes Java compilés ne soient pas des codes-barres, ou du code machine direct, le concept conditionnel est toujours cohérent. Eh bien, j’ai essayé d’éviter une technicité plus profonde en expliquant. J’espère avoir rendu le concept clair et démystifié. Je vous remercie.

Si vous effectuez un nombre fou de vérifications comme 100+, vous pouvez envisager une abstraction.

Vous avez des paquets entrants allant de 0 à 255. Vous en utilisez peut-être 150. Vous voudrez peut-être envisager quelque chose comme ci-dessous au lieu d’un commutateur de 150 identifiants.

 Packets[] packets = new Packets[150]; static { packets[0] = new Login(); packets[2] = new Logout(); packets[3] = new GetMessage(); packets[7] = new AddFriend(); packets[9] = new JoinGroupChat(); // etc... not going to finish. } static final byte[] INDEX_LIST = { 0, 2, 3, 7, 9, // etc... Not going to do it, but this will convert packet id to index. }; public void handlePacket(IncomingData data) { int id = data.readByte(); packets[INDEX_LIST[id]].execute(data); } 

Je devrais également souligner que la liste d’index n’est pas vraiment nécessaire et ralentirait probablement le code de toute façon. Ce n’était qu’une suggestion, donc vous n’avez pas d’emplacements vides. Aussi ne pas mentionner est cette situation que vous perdez seulement de 106 index. Je ne suis pas sûr à 100%, mais je pense que chacun de ces points pointe vers null de toute façon, donc aucun problème de mémoire réel ne serait présent.