web-dev-qa-db-fra.com

Java instruction switch de plusieurs cas

J'essaie juste de comprendre comment utiliser plusieurs cas multiples pour une instruction switch Java. Voici un exemple de ce que j'essaie de faire:

switch (variable)
{
    case 5..100:
        doSomething();
    break;
}

versus devoir faire:

switch (variable)
{
    case 5:
    case 6:
    etc.
    case 100:
        doSomething();
    break;
}

Des idées si cela est possible, ou quelle bonne alternative est?

102
FunJavaCode

Malheureusement, ce n'est pas possible en Java. Vous devrez recourir à des instructions if-else.

75
Bala R

La deuxième option est tout à fait correcte. Je ne sais pas pourquoi un intervenant a dit que ce n'était pas possible. C'est bien et je le fais tout le temps:

switch (variable)
{
    case 5:
    case 6:
    etc.
    case 100:
        doSomething();
    break;
}
72
Dave

Peut-être pas aussi élégant que certaines réponses précédentes, mais si vous voulez réaliser des cas de commutation avec peu de plages étendues, combinez simplement des plages à un cas unique auparavant:

// make a switch variable so as not to change the original value
int switchVariable = variable;

//combine range 1-100 to one single case in switch
if(1 <= variable && variable <=100)
    switchVariable = 1;
switch (switchVariable) 
{ 
    case 0:
        break; 
    case 1:
        // range 1-100
        doSomething(); 
        break;
    case 101: 
        doSomethingElse(); 
        break;
    etc.
} 
46
Santtu Kähkönen
public class SwitchTest {
    public static void main(String[] args){
        for(int i = 0;i<10;i++){
            switch(i){
                case 1: case 2: case 3: case 4: //First case
                    System.out.println("First case");
                    break;
                case 8: case 9: //Second case
                    System.out.println("Second case");
                    break;
                default: //Default case
                    System.out.println("Default case");
                    break;
            }
        }
    }
}

En dehors:

Default case
First case
First case
First case
First case
Default case
Default case
Default case
Second case
Second case

Src: http://docs.Oracle.com/javase/tutorial/Java/nutsandbolts/switch.html

43
P. Waksman

Une option orientée objet pour remplacer les constructions switch et if/else excessivement grandes consiste à utiliser un Chain of Responsibility Pattern pour modéliser la prise de décision.

Modèle de chaîne de responsabilité

Le modèle de chaîne de responsabilité permet de séparer la source d'une demande du choix du nombre potentiellement élevé de gestionnaires pour la demande qui doit la traiter. La classe représentant le rôle de chaîne canalise les demandes de la source dans la liste des gestionnaires jusqu'à ce qu'un gestionnaire accepte la demande et l'active.

Voici un exemple d'implémentation de type Safe utilisant Generics également.

import Java.util.ArrayList;
import Java.util.List;

/**
* Generic enabled Object Oriented Switch/Case construct
* @param <T> type to switch on
*/
public class Switch<T extends Comparable<T>>
{
    private final List<Case<T>> cases;

    public Switch()
    {
        this.cases = new ArrayList<Case<T>>();
    }

    /**
     * Register the Cases with the Switch
     * @param c case to register
     */
    public void register(final Case<T> c) { this.cases.add(c); }

    /**
     * Run the switch logic on some input
     * @param type input to Switch on
     */
    public void evaluate(final T type)
    {
        for (final Case<T> c : this.cases)
        {
            if (c.of(type)) { break; }
        }
    }

    /**
     * Generic Case condition
     * @param <T> type to accept
     */
    public static interface Case<T extends Comparable<T>>
    {
        public boolean of(final T type);
    }

    public static abstract class AbstractCase<T extends Comparable<T>> implements Case<T>
    {
        protected final boolean breakOnCompletion;

        protected AbstractCase()
        {
            this(true);
        }

        protected AbstractCase(final boolean breakOnCompletion)
        {
            this.breakOnCompletion = breakOnCompletion;
        }
    }

    /**
     * Example of standard "equals" case condition
     * @param <T> type to accept
     */
    public static abstract class EqualsCase<T extends Comparable<T>> extends AbstractCase<T>
    {
        private final T type;

        public EqualsCase(final T type)
        {
            super();
            this.type = type;
        }

        public EqualsCase(final T type, final boolean breakOnCompletion)
        {
            super(breakOnCompletion);
            this.type = type;
        }
    }

    /**
     * Concrete example of an advanced Case conditional to match a Range of values
     * @param <T> type of input
     */
    public static abstract class InRangeCase<T extends Comparable<T>> extends AbstractCase<T>
    {
        private final static int GREATER_THAN = 1;
        private final static int EQUALS = 0;
        private final static int LESS_THAN = -1;
        protected final T start;
        protected final T end;

        public InRangeCase(final T start, final T end)
        {
            this.start = start;
            this.end = end;
        }

        public InRangeCase(final T start, final T end, final boolean breakOnCompletion)
        {
            super(breakOnCompletion);
            this.start = start;
            this.end = end;
        }

        private boolean inRange(final T type)
        {
            return (type.compareTo(this.start) == EQUALS || type.compareTo(this.start) == GREATER_THAN) &&
                    (type.compareTo(this.end) == EQUALS || type.compareTo(this.end) == LESS_THAN);
        }
    }

    /**
     * Show how to apply a Chain of Responsibility Pattern to implement a Switch/Case construct
     *
     * @param args command line arguments aren't used in this example
     */
    public static void main(final String[] args)
    {
        final Switch<Integer> integerSwitch = new Switch<Integer>();
        final Case<Integer> case1 = new EqualsCase<Integer>(1)
        {
            @Override
            public boolean of(final Integer type)
            {
                if (super.type.equals(type))
                {
                    System.out.format("Case %d, break = %s\n", type, super.breakOnCompletion);
                    return super.breakOnCompletion;
                }
                else
                {
                    return false;
                }
            }
        };
        integerSwitch.register(case1);
        // more instances for each matching pattern, granted this will get verbose with lots of options but is just
        // and example of how to do standard "switch/case" logic with this pattern.
        integerSwitch.evaluate(0);
        integerSwitch.evaluate(1);
        integerSwitch.evaluate(2);


        final Switch<Integer> inRangeCaseSwitch = new Switch<Integer>();
        final Case<Integer> rangeCase = new InRangeCase<Integer>(5, 100)
        {
            @Override
            public boolean of(final Integer type)
            {
                if (super.inRange(type))
                {
                    System.out.format("Case %s is between %s and %s, break = %s\n", type, this.start, this.end, super.breakOnCompletion);
                    return super.breakOnCompletion;
                }
                else
                {
                    return false;
                }
            }
        };
        inRangeCaseSwitch.register(rangeCase);
        // run some examples
        inRangeCaseSwitch.evaluate(0);
        inRangeCaseSwitch.evaluate(10);
        inRangeCaseSwitch.evaluate(200);

        // combining both types of Case implementations
        integerSwitch.register(rangeCase);
        integerSwitch.evaluate(1);
        integerSwitch.evaluate(10);

    }
}

Ceci est juste un rapide homme de paille que j'ai préparé en quelques minutes, une implémentation plus sophistiquée pourrait permettre à une sorte de Command Pattern d'être injecté dans les instances de Case d'implémentations pour en faire plus d'un appel retour style IoC.

Une bonne chose à propos de cette approche est que les instructions Switch/Case concernent uniquement les effets secondaires. Celles-ci encapsulent les effets secondaires dans les classes de manière à pouvoir les gérer et les réutiliser mieux. ce n'est pas une mauvaise chose.

Je publierai toutes les mises à jour ou améliorations de ceci Gist sur Github.

20
user177800

Fondamentalement:

if (variable >= 5 && variable <= 100)
{
    doSomething();
}

Si vous avez vraiment besoin d'un commutateur, c'est que vous devez faire différentes choses pour certaines gammes. Dans ce cas, oui, vous allez avoir un code compliqué, parce que les choses deviennent complexes et que seules les choses qui suivent les modèles vont bien se compresser.

La seule raison d'un changement est d'économiser sur la saisie du nom de la variable si vous ne testez que des valeurs de commutation numériques. Vous n'allez pas allumer 100 choses, et elles ne vont pas toutes faire la même chose. Cela ressemble plus à un bloc "if".

6
Michael Kozakewich

Selon cette question , c'est totalement possible.

Rassemblez simplement tous les cas qui contiennent la même logique et ne mettez pas break derrière eux.

switch (var) {
    case (value1):
    case (value2):
    case (value3):
        //the same logic that applies to value1, value2 and value3
        break;
    case (value4):
        //another logic
        break;
}

C'est parce que case sans break va sauter à un autre case jusqu'à break ou return.

MODIFIER:

En réponse au commentaire, si nous avons vraiment 95 valeurs avec la même logique, mais un nombre beaucoup plus petit d'observations avec une logique différente, nous pouvons faire:

switch (var) {
     case (96):
     case (97):
     case (98):
     case (99):
     case (100):
         //your logic, opposite to what you put in default.
         break;
     default: 
         //your logic for 1 to 95. we enter default if nothing above is met. 
         break;
}

Si vous avez besoin d'un contrôle plus précis, if-else est le choix.

6
WesternGun

// Exemple de code non conforme

switch (i) {
  case 1:
    doFirstThing();
    doSomething();
    break;
  case 2:
    doSomethingDifferent();
    break;
  case 3:  // Noncompliant; duplicates case 1's implementation
    doFirstThing();
    doSomething();
    break;
  default:
    doTheRest();
}

if (a >= 0 && a < 10) {
  doFirstThing();

  doTheThing();
}
else if (a >= 10 && a < 20) {
  doTheOtherThing();
}
else if (a >= 20 && a < 50) {
  doFirstThing();
  doTheThing();  // Noncompliant; duplicates first condition
}
else {
  doTheRest();
}

// Solution conforme

switch (i) {
  case 1:
  case 3:
    doFirstThing();
    doSomething();
    break;
  case 2:
    doSomethingDifferent();
    break;
  default:
    doTheRest();
}

if ((a >= 0 && a < 10) || (a >= 20 && a < 50)) {
  doFirstThing();
  doTheThing();
}
else if (a >= 10 && a < 20) {
  doTheOtherThing();
}
else {
  doTheRest();
}
4
Manoj Kumar Sharma

Depuis la dernière version de Java-12, plusieurs constantes de la même étiquette de casse sont disponibles dans fonction de langage de prévisualisation

Il est disponible dans une version de JDK pour susciter les commentaires des développeurs basés sur une utilisation réelle. cela pourrait conduire à ce qu'il devienne permanent à l'avenir Java SE Platform.

On dirait:

switch(variable) {
    case 1 -> doSomething();
    case 2, 3, 4 -> doSomethingElse();
};

Voir plus JEP 325: Expressions de commutation (Aperçu)

1
Ruslan

Il est possible de gérer cela en utilisant la bibliothèque Vavr

import static io.vavr.API.*;
import static io.vavr.Predicates.*;

Match(variable).of(
    Case($(isIn(5, 6, ... , 100)), () -> doSomething()),
    Case($(), () -> handleCatchAllCase())
);

Il ne s'agit bien sûr que d'une légère amélioration, car tous les cas doivent encore être énumérés explicitement. Mais il est facile de définir un prédicat personnalisé:

public static <T extends Comparable<T>> Predicate<T> isInRange(T lower, T upper) {
    return x -> x.compareTo(lower) >= 0 && x.compareTo(upper) <= 0;
}

Match(variable).of(
    Case($(isInRange(5, 100)), () -> doSomething()),
    Case($(), () -> handleCatchAllCase())
);

La correspondance est une expression et renvoie ici quelque chose comme l’instance Runnable au lieu d’appeler directement des méthodes. Une fois la correspondance effectuée, Runnable peut être exécuté.

Pour plus de détails, voir documentation officielle .

1
hgrey

pour alternative vous pouvez utiliser comme ci-dessous:

if (variable >= 5 && variable <= 100) {
        doSomething();

    }

ou le code suivant fonctionne également

switch (variable)
{
    case 5:
    case 6:
    etc.
    case 100:
        doSomething();
    break;
}
1
asok

Une alternative au lieu d'utiliser des valeurs codées en dur pourrait être d'utiliser des mappages de plage sur l'instruction switch:

private static final int RANGE_5_100 = 1;
private static final int RANGE_101_1000 = 2;
private static final int RANGE_1001_10000 = 3;

public boolean handleRanges(int n) {
    int rangeCode = getRangeCode(n);
    switch (rangeCode) {
        case RANGE_5_100: // doSomething();
        case RANGE_101_1000: // doSomething();
        case RANGE_1001_10000: // doSomething();
        default: // invalid range
    }
}

private int getRangeCode(int n) {
    if (n >= 5 && n <= 100) {
        return RANGE_5_100;
    } else if (n >= 101 && n <= 1000) {
        return RANGE_101_1000;
    } else if (n >= 1001 && n <= 10000) {
        return RANGE_1001_10000;
    }

    return -1;
}
0
guilhebl