Réponses:
Parfois, il est utile d'avoir plusieurs cas associés au même bloc de code, tels que
case 'A':
case 'B':
case 'C':
doSomething();
break;
case 'D':
case 'E':
doSomethingElse();
break;
etc. Juste un exemple.
D'après mon expérience, il est généralement mauvais de «passer à travers» et d'exécuter plusieurs blocs de code pour un cas, mais il peut y avoir des utilisations pour cela dans certaines situations.
// Intentional fallthrough.
lorsque vous omettez une pause. Ce n'est pas tant un mauvais style que "facile d'oublier une pause accidentellement" à mon avis. PS Bien sûr pas dans des cas simples comme dans la réponse elle-même.
case
s sont empilés de cette façon. S'il y a du code entre eux, oui, le commentaire est probablement mérité.
case
, comme ceci case 'A','B','C': doSomething(); case 'D','E': doSomethingElse();
:, sans avoir besoin d'une pause entre les cas. Pascal pourrait faire cela: "L'instruction case compare la valeur de l'expression ordinale à chaque sélecteur, qui peut être une constante, un sous-intervalle ou une liste d'entre eux séparés par des virgules." ( wiki.freepascal.org/Case )
Historiquement , c'est parce que le case
définissait essentiellement un label
, également connu comme le point cible d'un goto
appel. L'instruction switch et ses cas associés ne représentent en réalité qu'une branche à plusieurs voies avec plusieurs points d'entrée potentiels dans un flux de code.
Cela dit, il a été noté un nombre presque infini de fois que break
c'est presque toujours le comportement par défaut que vous préférez avoir à la fin de chaque cas.
Java vient de C et c'est la syntaxe de C.
Il y a des moments où vous souhaitez que plusieurs instructions case n'aient qu'un seul chemin d'exécution. Vous trouverez ci-dessous un exemple qui vous indiquera le nombre de jours par mois.
class SwitchDemo2 {
public static void main(String[] args) {
int month = 2;
int year = 2000;
int numDays = 0;
switch (month) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
numDays = 31;
break;
case 4:
case 6:
case 9:
case 11:
numDays = 30;
break;
case 2:
if ( ((year % 4 == 0) && !(year % 100 == 0))
|| (year % 400 == 0) )
numDays = 29;
else
numDays = 28;
break;
default:
System.out.println("Invalid month.");
break;
}
System.out.println("Number of Days = " + numDays);
}
}
Je pense que c'est une erreur. En tant que construction de langage, il est tout aussi facile à avoir break
que la valeur par défaut et à la place d'avoir un fallthrough
mot - clé. La plupart du code que j'ai écrit et lu a une pause après chaque cas.
continue <case name>
ce qui permet de spécifier explicitement avec quelle déclaration de cas continuer;
case
dans le courant switch
, cela devient simplement un goto
. ;-)
Vous pouvez faire toutes sortes de choses intéressantes avec la chute des cas.
Par exemple, disons que vous voulez faire une action particulière pour tous les cas, mais dans un certain cas, vous voulez faire cette action plus autre chose. L'utilisation d'une instruction switch avec fall-through rendrait les choses assez faciles.
switch (someValue)
{
case extendedActionValue:
// do extended action here, falls through to normal action
case normalActionValue:
case otherNormalActionValue:
// do normal action here
break;
}
Bien sûr, il est facile d'oublier l' break
instruction à la fin d'un cas et de provoquer un comportement inattendu. Les bons compilateurs vous avertiront lorsque vous omettez l'instruction break.
Pourquoi le compilateur ne met-il pas automatiquement des instructions break après chaque bloc de code dans le commutateur?
Laissant de côté la bonne volonté de pouvoir utiliser le même bloc pour plusieurs cas (qui pourraient être à cas particulier) ...
Est-ce pour des raisons historiques? Quand voudriez-vous que plusieurs blocs de code s'exécutent?
C'est principalement pour la compatibilité avec C, et c'est sans doute un ancien hack de l'époque où les goto
mots - clés parcouraient la terre. Il ne permettra des choses étonnantes, bien sûr, comme le dispositif de Duff , mais que ce soit un point en sa faveur ou contre est ... argumentative au mieux.
Le break
commutateur after case
est utilisé pour éviter la chute dans les instructions switch. Bien que cela soit intéressant, cela peut maintenant être réalisé grâce aux nouvelles étiquettes de commutation mises en œuvre via JEP-325 .
Avec ces changements, le break
avec chaque commutateur case
peut être évité comme démontré plus loin: -
public class SwitchExpressionsNoFallThrough {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int value = scanner.nextInt();
/*
* Before JEP-325
*/
switch (value) {
case 1:
System.out.println("one");
case 2:
System.out.println("two");
default:
System.out.println("many");
}
/*
* After JEP-325
*/
switch (value) {
case 1 ->System.out.println("one");
case 2 ->System.out.println("two");
default ->System.out.println("many");
}
}
}
Lors de l' exécution du code ci-dessus avec JDK-12 , la sortie comparative pourrait être considérée comme
//input
1
// output from the implementation before JEP-325
one
two
many
// output from the implementation after JEP-325
one
et
//input
2
// output from the implementation before JEP-325
two
many
// output from the implementation after JEP-325
two
et bien sûr la chose inchangée
// input
3
many // default case match
many // branches to 'default' as well
Vous n'avez donc pas à répéter le code si vous avez besoin de plusieurs cas pour faire la même chose:
case THIS:
case THAT:
{
code;
break;
}
Ou vous pouvez faire des choses comme:
case THIS:
{
do this;
}
case THAT:
{
do that;
}
En cascade.
Vraiment sujet aux bogues / confusion, si vous me demandez.
do this
et do that
pour ceci mais juste do that
pour cela?
En ce qui concerne le dossier historique, Tony Hoare a inventé l'énoncé de cas dans les années 1960, pendant la révolution de la «programmation structurée». La déclaration de cas de Tony prenait en charge plusieurs étiquettes par cas et une sortie automatique sans break
déclarations puantes . L'exigence d'un explicite break
était quelque chose qui sortait de la ligne BCPL / B / C. Dennis Ritchie écrit (dans ACM HOPL-II):
Par exemple, la terminaison qui s'échappe d'une instruction switchon BCPL n'était pas présente dans le langage lorsque nous l'avons appris dans les années 1960, et donc la surcharge du mot-clé break pour échapper à l'instruction switch B et C est due à une évolution divergente plutôt qu'à consciente changement.
Je n'ai pas pu trouver d'écrits historiques sur BCPL, mais le commentaire de Ritchie suggère que break
c'était plus ou moins un accident historique. BCPL a résolu le problème plus tard, mais peut-être que Ritchie et Thompson étaient trop occupés à inventer Unix pour être dérangés par un tel détail :-)
break
autorise "l'exécution de plusieurs blocs de code", et se préoccupe davantage de la motivation de ce choix de conception. D'autres ont mentionné l'héritage bien connu de C à Java, et cette réponse a poussé la recherche encore plus loin aux jours pré-C. J'aurais aimé avoir cette correspondance de motifs (bien que très primitive) dès le début.
Java est dérivé de C, dont l'héritage comprend une technique connue sous le nom de Duff's Device . C'est une optimisation qui repose sur le fait que le contrôle passe d'un cas à l'autre, en l'absence de break;
déclaration. Au moment où C a été normalisé, il y avait beaucoup de code comme celui-là "dans la nature", et il aurait été contre-productif de changer le langage pour casser de telles constructions.
Comme les gens l'ont déjà dit, il s'agit de permettre des retombées et ce n'est pas une erreur, c'est une fonctionnalité. Si trop d' break
instructions vous ennuient, vous pouvez facilement vous en débarrasser en utilisant des return
instructions à la place. C'est en fait une bonne pratique, car vos méthodes doivent être aussi petites que possible (pour des raisons de lisibilité et de maintenabilité), donc une switch
instruction est déjà assez grande pour une méthode, par conséquent, une bonne méthode ne doit contenir rien d'autre, c'est un exemple:
public class SwitchTester{
private static final Log log = LogFactory.getLog(SwitchTester.class);
public static void main(String[] args){
log.info(monthsOfTheSeason(Season.WINTER));
log.info(monthsOfTheSeason(Season.SPRING));
log.info(monthsOfTheSeason(Season.SUMMER));
log.info(monthsOfTheSeason(Season.AUTUMN));
}
enum Season{WINTER, SPRING, SUMMER, AUTUMN};
static String monthsOfTheSeason(Season season){
switch(season){
case WINTER:
return "Dec, Jan, Feb";
case SPRING:
return "Mar, Apr, May";
case SUMMER:
return "Jun, Jul, Aug";
case AUTUMN:
return "Sep, Oct, Nov";
default:
//actually a NullPointerException will be thrown before reaching this
throw new IllegalArgumentException("Season must not be null");
}
}
}
L'exécution imprime:
12:37:25.760 [main] INFO lang.SwitchTester - Dec, Jan, Feb
12:37:25.762 [main] INFO lang.SwitchTester - Mar, Apr, May
12:37:25.762 [main] INFO lang.SwitchTester - Jun, Jul, Aug
12:37:25.762 [main] INFO lang.SwitchTester - Sep, Oct, Nov
comme prévu.
Le fait de ne pas avoir de pause automatique ajoutée par le compilateur permet d'utiliser un commutateur / cas pour tester des conditions comme 1 <= a <= 3
en supprimant l'instruction break de 1 et 2.
switch(a) {
case 1: //I'm between 1 and 3
case 2: //I'm between 1 and 3
case 3: //I'm between 1 and 3
break;
}
C'est une vieille question, mais en fait, je suis tombé sur l'utilisation du cas sans déclaration de rupture aujourd'hui. Ne pas utiliser break est en fait très utile lorsque vous devez combiner différentes fonctions en séquence.
par exemple en utilisant des codes de réponse http pour authentifier l'utilisateur avec un jeton de temps
code de réponse du serveur 401 - le jeton est obsolète -> régénérer le jeton et connecter l'utilisateur.
code de réponse du serveur 200 - le jeton est OK -> connecter l'utilisateur.
dans les déclarations de cas:
case 404:
case 500:
{
Log.v("Server responses","Unable to respond due to server error");
break;
}
case 401:
{
//regenerate token
}
case 200:
{
// log in user
break;
}
En utilisant cela, vous n'avez pas besoin d'appeler la fonction utilisateur de connexion pour la réponse 401 car lorsque le jeton est régénéré, le runtime saute dans le cas 200.
Vous pouvez facilement séparer d'autres types de nombre, de mois, de décompte.
C'est mieux alors si dans ce cas;
public static void spanishNumbers(String span){
span = span.toLowerCase().replace(" ", "");
switch (span){
case "1":
case "jan": System.out.println("uno"); break;
case "2":
case "feb": System.out.println("dos"); break;
case "3":
case "mar": System.out.println("tres"); break;
case "4":
case "apr": System.out.println("cuatro"); break;
case "5":
case "may": System.out.println("cinco"); break;
case "6":
case "jun": System.out.println("seis"); break;
case "7":
case "jul": System.out.println("seite"); break;
case "8":
case "aug": System.out.println("ocho"); break;
case "9":
case "sep": System.out.println("nueve"); break;
case "10":
case "oct": System.out.println("diez"); break;
}
}
Je travaille maintenant sur un projet dont j'ai besoin break
dans mon instruction switch, sinon le code ne fonctionnera pas. Soyez avec moi et je vais vous donner un bon exemple de pourquoi vous break
en avez besoin dans votre déclaration de changement.
Imaginez que vous ayez trois états, l'un qui attend que l'utilisateur entre un nombre, le second pour le calculer et le troisième pour imprimer la somme.
Dans ce cas, vous avez:
En regardant les états, vous voudriez que l'ordre d'exaction commence sur state1 , puis state3 et enfin state2 . Sinon, nous n'imprimerons que les entrées des utilisateurs sans calculer la somme. Juste pour clarifier à nouveau, nous attendons que l'utilisateur entre une valeur, puis calculons la somme et imprime la somme.
Voici un exemple de code:
while(1){
switch(state){
case state1:
// Wait for user input code
state = state3; // Jump to state3
break;
case state2:
//Print the sum code
state = state3; // Jump to state3;
case state3:
// Calculate the sum code
state = wait; // Jump to state1
break;
}
}
Si nous ne l'utilisons pas break
, il s'exécutera dans cet ordre, état1 , état2 et état3 . Mais en utilisant break
, nous évitons ce scénario, et pouvons commander dans la bonne procédure qui est de commencer par state1, puis state3 et last but not least state2.
break
.