Istruzione switch Java più casi


118

Sto solo cercando di capire come utilizzare molti casi multipli per un'istruzione switch Java. Ecco un esempio di quello che sto cercando di fare:

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

rispetto a dover fare:

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

Qualche idea, se possibile, o quale buona alternativa è?


12
Sembra che tu stia usando numeri interi, quindi suppongo che se sai che i tuoi intervalli sono di una dimensione fissa, potresti sempre cambiare (variabile / FIXED_SIZE_OF_RANGE) {case 0: ... default: break; }
paulrehkugler

Risposte:


80

Purtroppo, non è possibile in Java. Dovrai ricorrere all'uso di if-elsedichiarazioni.


1
@ FunJavaCode AFAIK puoi farlo in vb.net. Ecco un esempio
Bala R

1
@YuryLitvinov vuoi espandere il motivo per cui pensi che non sia corretto?
Bala R

1
La mia risposta dimostra che questo non è corretto, è OO ed è un modello noto e accettato per affrontare questo problema esatto tra gli altri che richiedono molte if/elseif/elseaffermazioni annidate , indipendentemente dal linguaggio.

1
E 'possibile ottenere la condizione OR nel caso switch utilizzando questi link ... plz controllarlo fuori: - stackoverflow.com/a/16706729/3946958
Ravindra Kushwaha

4
bro il suo possibile utilizzo può scrivere più maiuscole senza utilizzare break e alla fine di case puoi scrivere la tua logica come: case some_value: case some_value: case some_value: you_logic_goes_here break;
anoopbryan2

85

La seconda opzione va benissimo. Non sono sicuro del motivo per cui un risponditore ha detto che non era possibile. Va bene, e lo faccio sempre:

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

50
L'interrogante ha detto di fare questo "contro" farlo. Capisce che ciò che hai elencato è valido, stava cercando di fare la prima cosa INVECE di quella.
Blaine Mucklow

45
Mi dispiace, ma non vedo come elencare 95 casi di fila che vanno alla stessa cosa sia una soluzione a qualsiasi cosa. Se lo avessi riscontrato in qualsiasi codice, li avrei rintracciati, rapiti, consegnati personalmente a GLaDOS e spero che dia loro la sequenza di test più letale che riesce a trovare.
animuson

1
@animuson, inoltre, viene votato 60 volte .... vai a capire. Sono venuto qui perché non volevo fare la cosa ESATTA a cui risponde
killjoy

Downvoting in quanto questo non risponde alla domanda. . .heck, a quanto pare, la domanda non è stata nemmeno letta per poter scrivere questa risposta.
iheanyi

50
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;
            }
        }
    }
}

Su:

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


4
Questo è lo stesso della parte "contro" della sua domanda, che voleva evitare.
Bdoserror

2
Le risposte solo il codice sono dannose quasi quanto le risposte solo i link. Non sono affatto risposte. Una buona risposta contiene spiegazioni e ragionamenti e possibilmente alcune fonti o autorità.
markus

3
È meglio di niente, alcune persone la considerano la risposta migliore, semplice e diretta
D4rWiNS

48

Forse non così elegante come alcune risposte precedenti, ma se vuoi ottenere custodie per interruttori con poche gamme di grandi dimensioni, combina in anticipo le gamme a una singola custodia:

// 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.
} 

11
Non lo consiglierei. Se esegui semplicemente il codice, avrai l'intuizione che case 1significa variable == 1, il che porta a confusione e molto dolore a lungo termine. Se hai bisogno di inserire commenti nel tuo codice per renderlo leggibile, hai fatto qualcosa di sbagliato IMHO.
kraxor

21

Un oggetto opzione Oriented per sostituire troppo grande switche if/elsecostrutti è quello di utilizzare un Chain of Responsibility Patternper modellare il processo decisionale.

Schema della catena di responsabilità

Il modello della catena di responsabilità consente di separare l'origine di una richiesta dal decidere quale tra il numero potenzialmente elevato di gestori della richiesta deve agire. La classe che rappresenta il ruolo della catena canalizza le richieste dall'origine lungo l'elenco di gestori finché un gestore non accetta la richiesta e la attiva.

Ecco un'implementazione di esempio che è anche Type Safe utilizzando Generics.

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);

    }
}

Questo è solo un uomo di paglia veloce che ho scatenato in pochi minuti, un più sofisticato attuazione potrebbe consentire un qualche tipo di Command Patternessere iniettato nelle Caseistanze di implementazioni per renderlo più di una schiena chiamata stile CIO.

Una volta la cosa bella di questo approccio è che le dichiarazioni Switch / Case riguardano gli effetti collaterali, questo incapsula gli effetti collaterali nelle classi in modo che possano essere gestiti e riutilizzati meglio, finisce per essere più simile al Pattern Matching in un linguaggio funzionale e non è una brutta cosa.

Pubblicherò eventuali aggiornamenti o miglioramenti a questo Gist su GitHub.


2
Sono d'accordo, le istruzioni case e i blocchi big if sono fastidiosi se hai una grande quantità di variabili. Se stai facendo molte dichiarazioni di casi, non stai usando i principi OO come potresti essere.
Blaine Mucklow

11

Secondo questa domanda , è totalmente possibile.

Metti insieme tutti i casi che contengono la stessa logica e non metterli breakdietro.

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

È perché casesenza breakpasserà a un altro casefino a quando breako return.

MODIFICARE:

Rispondendo al commento, se abbiamo davvero 95 valori con la stessa logica, ma un numero molto minore di casi con logica diversa, possiamo fare:

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;
}

Se hai bisogno di un controllo più preciso, if-elseè la scelta.


2
La domanda offre già questo come soluzione e chiede se esiste un modo per specificare un intervallo senza dover codificare ogni valore nell'intervallo (OP richiederebbe 96 caseistruzioni!). Temo di essere d'accordo con la risposta accettata.
Bohemian

Grazie per il commento. Vedi modifica, forse. Sono d'accordo che tutto dipende dallo scenario e 5 contro 95 potrebbe non essere il caso.
WesternGun

6

Fondamentalmente:

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

Se davvero avessi bisogno di usare un interruttore, sarebbe perché devi fare varie cose per determinati intervalli. In tal caso, sì, avrai codice disordinato, perché le cose stanno diventando complesse e solo le cose che seguono gli schemi si comprimeranno bene.

L'unico motivo per un interruttore è risparmiare sulla digitazione del nome della variabile se stai solo testando i valori di commutazione numerici. Non accenderete 100 cose e non faranno tutte la stessa cosa. Sembra più un pezzo "se".


4

// Esempio di codice 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();
}

// Soluzione 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();
}

La vera risposta che meritava il pollice in alto. Bello.
user1735921

3

Dall'ultima versione java-12 più costanti nella stessa etichetta del caso sono disponibili nella funzione di anteprima della lingua

È disponibile in una versione di funzionalità JDK per provocare il feedback degli sviluppatori in base all'uso nel mondo reale; questo potrebbe far sì che diventi permanente in una futura piattaforma Java SE.

Sembra:

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

Ulteriori informazioni su JEP 325: Cambia espressioni (anteprima)


2

È possibile gestirlo utilizzando la libreria Vavr

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

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

Questo è ovviamente solo un leggero miglioramento poiché tutti i casi devono ancora essere elencati esplicitamente. Ma è facile definire un predicato personalizzato:

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())
);

Match è un'espressione quindi qui restituisce qualcosa come Runnableistanza invece di invocare direttamente i metodi. Dopo che la corrispondenza è stata eseguita Runnablepuò essere eseguita.

Per ulteriori dettagli, consultare la documentazione ufficiale .


1

in alternativa puoi usare come di seguito:

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

    }

oppure funziona anche il codice seguente

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

1

JEP 354: Switch Expressions (Preview) in JDK-13 e JEP 361: Switch Expressions (Standard) in JDK-14 estenderà l' istruzione switch in modo che possa essere utilizzata come espressione .

Ora puoi:

  • assegna direttamente la variabile dall'espressione switch ,
  • usa la nuova forma di etichetta interruttore ( case L ->):

    Il codice a destra di un'etichetta switch "case L ->" è limitato ad essere un'espressione, un blocco o (per comodità) un'istruzione throw.

  • usa più costanti per caso, separate da virgole,
  • e inoltre non ci sono più interruzioni di valore :

    Per ottenere un valore da un'espressione switch, l' breakistruzione with value viene eliminata a favore di yieldun'istruzione.

Cambia esempio di espressione:

public class SwitchExpression {

  public static void main(String[] args) {
      int month = 9;
      int year = 2018;
      int numDays = switch (month) {
        case 1, 3, 5, 7, 8, 10, 12 -> 31;
        case 4, 6, 9, 11 -> 30;
        case 2 -> {
          if (java.time.Year.of(year).isLeap()) {
            System.out.println("Wow! It's leap year!");
            yield 29;
          } else {
            yield 28;
          }
        }
        default -> {
          System.out.println("Invalid month.");
          yield 0;
        }
      };
      System.out.println("Number of Days = " + numDays);
  }
}

0

Un'alternativa invece di utilizzare valori hardcoded potrebbe essere l'utilizzo di mapping di intervallo sull'istruzione 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;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.