Quand utiliser une instruction switch en Java


J'apprécie que tout ce qui peut être fait par une déclaration de commutateur, peut être fait par une instruction if else.

Mais existe-t-il des règles stylistiques pour savoir quand il faut utiliser le commutateur plutôt que if else statment.

Author: namalfernandolk, 2010-01-20

16 answers

Eh Bien, switch se sent plus "léger" dans de nombreux cas qu'un if/else if échelle, à mon avis. Fondamentalement, vous n'avez pas beaucoup de syntaxe avec des accolades et des parenthèses à la manière de votre code. Cela étant dit, switch hérite de la syntaxe de C. Cela signifie que vous avez break et une seule portée pour les variables, sauf si vous introduisez de nouveaux blocs.

Néanmoins, le compilateur est capable d'optimiser les instructions switch dans une table de recherche et d'effectuer une vérification au moment de la compilation des littéraux lorsqu'il s'agit d'énumérations. Donc, je suggère qu'il est généralement préférable d'utiliser switch sur if/else if si vous avez affaire à des types numériques ou enum.

 15
Author: Joey, 2015-11-30 19:33:14

Switch a un avantage en matière de clarté:

switch (i) {
  case 1:
    // do something
    break;
  case 2:
  case 4:
    // do something
    break;
  case 5:
    // do something
    break;
}

Si le code pour 2 et 4 est identique, il peut être plus clair que:

if ( i == 1 ) {
  // do something
}
if ( (i == 2) || (i == 4) ) {
  // do something
}
if ( (i == 5 ) {
  // do something
}

, Il est aussi plus facile pour vous (ou un autre programmeur) pour répartir les 2 et 4 cas.

 10
Author: Armstrongest, 2011-05-18 12:56:24

J'utilise des instructions switch pour les énumérations, il est plus lisible qu'une instruction if else if else if. Cependant, vous devriez essayer d'éviter de tels contrôles dans une conception OO.

 5
Author: bertolami, 2010-01-20 16:39:53

Vous utilisez une instruction switch lorsque vous activez différentes valeurs de types primitifs / enum / wrapper. (Et pas tous les types primitifs / wrapper, juste ceux pris en charge - byte, short, char, int).

If/else gère le reste.

Par exemple, il est plus esthétique de dire:

int i = getValueOfI();
switch (i) {
  case 1:
    // do something
    break;
  case 2:
    // do something
    break;

Etc.

Que

if (i == 1) {

} else if (i == 2) {

}...

Pour un grand nombre de cas. Mais vous ne pouvez pas activer les chaînes, les valeurs de fonction ou les conditions complexes, donc si vous devez faire de cela, vous êtes coincé avec if / else.

 4
Author: danben, 2010-01-20 16:38:49

Personnellement, je trouve les deux constructions un peu trop procédurales. Bien qu'il puisse être considéré comme un extermisme OO, j'utilise une carte contenant des instances d'une interface interne pour chaque cas de l'if. Cela permet une meilleure isolation du code, je pense. Cependant, pour répondre sincèrement à votre question, je n'utilise switchs que lorsque j'ai des cas qui se chevauchent vraiment (le, je n'utilise pas d'instructions break). Malheureusement, ce n'est vraiment pas un bloc de code maintenable.

 3
Author: Riduidel, 2010-01-20 16:42:21

Je suggère la règle simple:

Utilisez toujours un switch lorsque vous avez au moins 2 options à différencier, lorsque le type de données est utilisable pour un commutateur et lorsque toutes les options ont des valeurs constantes.

Il y a trois bonnes raisons. Un, dans la plupart des cas switch est plus rapide qu'un if/else cascade. Deuxièmement, cela rend l'intention du code plus claire. Trois, le oh si mauvais oublié break dilemme est un moindre mal que énorme if/else cascades qui cassent accidentellement parce que quelqu'un a oublié un else.

Les machines virtuelles Java prennent en charge deux types de commutateurs différents: le tableswitch et l'instruction lookupswitch. Le tableswitch est généré par le compilateur si toutes les constantes case se trouvent dans une plage étroite, sinon il génère un lookupswitch. Pour les grandes instructions switch avec de nombreux cas, le tableswitch est plus efficace que le lookupswitch. Le lookupswitch est généralement implémenté par une forme de recherche binaire.

 3
Author: x4u, 2015-11-30 19:38:23

Il y a deux facteurs pour moi:

Lisibilité et si vous souhaitez décider quelque chose en utilisant des plages de valeurs ou de conditions (dans les instructions switch, vous ne pouvez utiliser qu'un seul entier ou une valeur énumérée).

 2
Author: Alex, 2010-01-20 16:39:56

Tout d'Abord, l'instruction switch doit être utilisable. Si le commutateur est basé sur la valeur d'une variable, alors il peut être utilisé. S'il est basé sur une expression booléenne complexe ET/OU/NON qui varie pour chaque condition, vous ne pouvez pas l'utiliser du tout.

Cela étant dit, s'il est applicable, et qu'il y a au moins 2 cas, alors j'utilise le commutateur. Il est plus facilement extensible, facile à lire et à vérifier.

 1
Author: Larry Watanabe, 2010-01-20 16:39:08

Commutateur et énumérations.

Si la valeur enum que vous testez peut légitimement être null pour une raison quelconque, la mettre dans l'instruction switch générera une NullPointerException. Sans regarder le code octet c'est un peu décevant qu'il le ferait.

L'explication: les énumérations sont du sucre syntaxique introduit en 1.5. L'instruction Switch fonctionne toujours avec des ints de bonne qualité, mais les valeurs qu'elle utilise sont des ordinaux affectés à enum. Pour obtenir l'ordinal, la valeur enum DOIT être non null.

if statement, d'autre part, serait heureux d'accepter null pour une valeur d'enum et simplement de ne pas le tester sans NPE.

 1
Author: Alexander Pogrebnyak, 2010-01-20 17:06:34

Peut-être un peu offtopic, mais si je répondais juste à la question dans le titre, alors je dirais que vous ne devriez pas utiliser switch dans toutes les situations où les cas représentent les états d'un objet. Le modèle d'état est une solution beaucoup plus jolie dans ces cas.

 1
Author: Roman, 2010-01-20 17:13:18

J'ai toujours trouvé que l'instruction java switch n'est pas aussi puissante que nécessaire. Dans son dernière version lambdaj implémente, avec une utilisation intelligente de la fermeture et de Hamcrest matcher.

Par exemple le lambdaj Switcher permet de mettre en œuvre un modèle de stratégie. Supposons que vous deviez basculer entre trois algorithmes de tri basés sur une caractéristique de la liste à trier. En particulier, supposons que nous avons un algorithme spécialisé pour Chaînes:

public List<String> sortStrings(List<String> list) {
    // a sort algorithm suitable for Strings
}

Un autre qui fonctionne bien avec les petites listes n'ayant pas plus de 100 éléments:

public List<T> sortSmallList(List<T> list) {
    // a sort algorithm suitable for no more than 100 items
}

Et un but plus général:

public List<String> sort(List<String> list) {
    // a generic sort algorithm
}

Compte tenu de ces 3 méthodes de tri, il est possible de créer une stratégie qui choisit la plus appropriée d'entre elles de la manière déclarative suivante:

Switcher<List<T>> sortStrategy = new Switcher<List<T>>()
    .addCase(having(on(List.class).get(0), instanceOf(String.class))), 
        new Closure() {{ of(this).sortStrings(var(List.class)); }})
    .addCase(having(on(List.class).size(), lessThan(100))), 
        new Closure() {{ of(this).sortSmallList(var(List.class)); }})
    .setDefault(new Closure() {{ of(this).sort(var(List.class)); }});

Et trier une liste en utilisant le meilleur algorithme disponible en appelant le commutateur:

List<T> sortedList = sortStrategy.exec(list, list);
 1
Author: Mario Fusco, 2010-03-28 13:59:34

La réponse dépend de ce que vous faites exactement ainsi que de la répartition des choix.

Si une condition est dominante alors le si/alors est approprié.

if (i == 1){
  //do something
}else if (i == 2){
   // do something else
}

Si les conditions sont réparties uniformément, l'optimisation dans le compilateur fournira un avantage de performance. Cette différence de performance devient plus prononcée à mesure que le nombre de choix possibles augmente.

switch (i) {
  case 1:
     // do something
     break;
  case 2:
     // do something else
     break;
  ....
  case N: 
     // do yet something else
     break;
  }

Cela dit, si la performance n'est PAS importante, allez avec lequel vous vous approchez préférez comme le plus lisible (maintenable et plus facile à écrire).

Si d'autre part, si votre code est dans un hotspot où les performances SONT importantes, vous devriez aller avec le commutateur.

Pour les conditions "extrêmement grandes", l'exemple de Mario du commutateur lambdaj est vraiment cool et avec soin sur l'initialisation se traduira par des performances très élevées. C'est un codage très similaire à ce que l'optimiseur génère. Je définirais "extrêmement grand" comme lorsque le nombre d'options est assez grand ou complexe pour que cela vaille la peine de taper tout cela, et vaut la peine de la confusion de support lorsqu'un développeur de suivi essaie de parcourir le code. (Commentez votre code avec pourquoi vous avez tout cela!).

 1
Author: theCTO, 2012-09-13 13:03:44

Si vous avez trop de conditions à vérifier d'un type similaire, vous pouvez opter pour switch.

 0
Author: GuruKulki, 2010-01-20 16:39:18

, Comme avec d'autres langages tels que C ou C++, les instructions switch sont utiles lorsque vous voulez comparer une variable donnée avec une liste de valeurs possibles et effectuer une action en fonction de ces valeurs. C'est plus terne que si d'autres déclarations.

 0
Author: Otávio Décio, 2010-01-20 16:39:20

Je suis d'accord avec la réponse de x4u.

De plus, il y a une autre instance non mentionnée, encore, où je pense qu'il est préférable d'utiliser if-else blocs plutôt qu'un switch: lorsque des conditions supplémentaires dans chacun des blocs case sont testées avec des blocs if. Je vois ce mélange tout le temps dans le code existant.

, Par exemple je viens de tomber sur ce code qui a un switch sur une chaîne type, puis le vérifie une deuxième chaîne extension à l'aide d'un if deux case déclaration.

 public abstract class Temp {

    boolean valid;

    public Temp() {
        String type = getType();
        String extension = getFilenameExtension();
        switch(type) {
            case "Image File": {
                if(!".jpg".equals(extension) && !".png".equals(extension)) {
                    warnWrongImageFormat();
                    valid = false;
                }
                break;
            }
            case "Zip File": {
                if(!".zip".equals(extension)) {
                    warnWrongZipFormat();
                    valid = false;
                }
                break;
            }
            default: {
                valid = true;
                break;
            }
        }
    }

    abstract String getType();
    abstract String getFilenameExtension();
    abstract void warnWrongImageFormat();
    abstract void warnWrongZipFormat();
}

Au lieu de cela, il est beaucoup plus propre et moins complexe de réduire cela à un if else

public abstract class Temp {

    boolean valid;

    public Temp() {
        String type = getType();
        String extension = getFilenameExtension();
        valid = true;
        if("Image File".equals(type) && !".jpg".equals(extension) && !".png".equals(extension)) {
            warnWrongImageFormat();
            valid = false;
        }
        else if("Zip File".equals(type) && !".zip".equals(extension)) {
            warnWrongZipFormat();
            valid = false;
        }
    }

    abstract String getType();
    abstract String getFilenameExtension();
    abstract void warnWrongImageFormat();
    abstract void warnWrongZipFormat();
}
 0
Author: Kirby, 2017-05-23 12:16:55

Commutateur a deux inconvénients pertinents:

  • il est limité aux types primitifs et aux énumérations
  • vous devez vous rappeler "break", ce qui pourrait conduire à des bugs pas si évidents

Souvent, switch est un signe de mauvaise conception OO, car vous feriez mieux d'utiliser le polymorphisme.

Le seul avantage possible de switch est, qu'il est plus lisible. Mais est

switch (i) {
  case 1:
    // do something
    break;
  case 2:
    // do something
    break;
}

Plus lisible que ceci:

if (i == 1)
  //do something
else if (i == 2)
  // do something else

Je dirais: non! Et vous n'auriez pas les inconvénients de commutateur.

Ma suggestion: Essayez d'éviter switch.

 -1
Author: deamon, 2010-01-20 16:53:18