Switch-Anweisung mit jeweils einem Wertebereich verwenden?

91

Ist es in Java möglich, eine switch-Anweisung zu schreiben, bei der jeder Fall mehr als einen Wert enthält? Zum Beispiel (obwohl der folgende Code eindeutig nicht funktioniert):

switch (num) {
    case 1 .. 5:
        System.out.println("testing case 1 to 5");
        break;
    case 6 .. 10:
        System.out.println("testing case 6 to 10");
        break;
}

Ich denke, dass dies in Ziel C möglich ist. Gibt es eine ähnliche Sache in Java? Oder sollte ich nur if, else ifAussagen statt?

davidx1
quelle
Es gibt sogar Erweiterungen in einfachem C, die dies ermöglichen.
Arshajii

Antworten:

97

Java hat nichts dergleichen. Warum nicht einfach folgendes tun?

public static boolean isBetween(int x, int lower, int upper) {
  return lower <= x && x <= upper;
}

if (isBetween(num, 1, 5)) {
  System.out.println("testing case 1 to 5");
} else if (isBetween(num, 6, 10)) {
  System.out.println("testing case 6 to 10");
}
fehlender Faktor
quelle
1
Das funktioniert super und ist einfach. Auch wenn Sie Zahlen auswählen möchten, die nicht im Bereich liegen, brauchen Sie nur if (! IsBetween ..., gute Arbeit.
A54studio
1
@missingfaktor Ich habe deine Antwort etwas kritisiert . Sie möchten also wahrscheinlich etwas antworten. +1 obwohl.
Alexander Malakhov
@MCEmperor, bitte bearbeiten Sie meine Antwort nicht mit Ihren persönlichen Formatierungseinstellungen. Das ist keine nützliche Bearbeitung.
fehlender Faktor
@missingfaktor Sorry. Aber diese Änderung wurde vor langer Zeit genehmigt; Ich erinnerte mich nicht einmal daran, dass ich das jemals getan hatte.
MC Emperor
76

Mit switchAussagen kann man dieser Art von Verhalten am nächsten kommen

switch (num) {
case 1:
case 2:
case 3:
case 4:
case 5:
     System.out.println("1 through 5");
     break;
case 6:
case 7:
case 8:
case 9:
case 10:
     System.out.println("6 through 10");
     break;
}

Verwenden Sie ifAnweisungen.

Jeffrey
quelle
29

Eine andere Alternative ist die Verwendung der mathematischen Operation durch Teilen, zum Beispiel:

switch ((int) num/10) {
    case 1:
        System.out.println("10-19");
        break;
    case 2:
        System.out.println("20-29");
        break;
    case 3:
        System.out.println("30-39");
        break;
    case 4:
        System.out.println("40-49");
        break;
    default:
        break;
}

Wie Sie sehen, kann dies jedoch nur verwendet werden, wenn der Bereich jeweils festgelegt ist.

Hayi Nukman
quelle
6
Dies funktioniert gut mit http-Statuscodes geteilt durch 100.
Stefan
13

Ich glaube nicht, dass Sie das in Java tun können. Am besten setzen Sie den Code einfach in den letzten Fall des Bereichs.

switch (num) {
  case 1: case 2: case 3: case 4: case 5: 
     System.Out.Println("testing case 1 to 5");
     break;
  case 6: case 7: case 8: case 9: case 10:
     System.Out.Println("testing case 6 to 10");
     break;
  default:
     //
}
blitzen
quelle
9

Ich weiß, dass dieser Beitrag alt ist, aber ich glaube, dass diese Antwort eine gewisse Anerkennung verdient. Die switch-Anweisung muss nicht vermieden werden. Dies kann in Java erfolgen, jedoch über die switch-Anweisung, nicht über die Fälle. Dabei werden ternäre Operatoren verwendet.

public class Solution {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int num = Integer.parseInt(sc.nextLine());

        switch ((1 <= num && num <= 5 ) ? 0 :
                (6 <= num && num <= 10) ? 1 : 2) {

            case 0:
                System.out.println("I'm between one and five inclusive.");
                break;
            case 1:
                System.out.println("I'm between 6 and 10 inclusive.");
                break;
            case 2:
                System.out.println("I'm not between one and five or 6 and 10 inclusive.");
                break;
        }
    }
}
DarkHark
quelle
1
Schöne Lösung! Mit Java 7 und höher können Sie auch einen String einschalten, damit Ihre Fälle noch selbstdokumentierender sind, z . B. switch ((1 <= num && num <= 5 ) ? "1 .. 5" : ...und dann case "1 .. 5":.
Daniel Widdis
9
  case 1: case 2: case 3: case 4: case 5: 
         System.out.println("testing case 1 to 5");
         break;
  case 6: case 7: case 8: case 9: case 10:
         System.out.println("testing case 6 to 10");
         break;
  default:
         System.out.println("default"); 
Jitendra
quelle
5

Versuchen Sie dies, wenn Sie den Schalter verwenden müssen.

public static int range(int num){ 
    if ( 10 < num && num < 20)
        return 1;
    if ( 20 <= num && num < 30)
        return 2;
    return 3;
}

public static final int TEN_TWENTY = 1;
public static final int TWENTY_THIRTY = 2;

public static void main(String[]args){
    int a = 110;
    switch (range(a)){
        case TEN_TWENTY: 
            System.out.println("10-20"); 
            break;
        case TWENTY_THIRTY: 
            System.out.println("20-30"); 
            break;
        default: break;
    }
}
zl9394
quelle
Kannst du bitte auch eine Erklärung geben?
user1140237
Der Funktionsbereich gibt einen Wert gemäß dem Eingabeargument zurück, sodass hier die Erkennung des "Wertebereichs" in Verbindung mit der Switch-Case-Klausel durchgeführt werden kann.
zl9394
Dies funktioniert für meinen Anwendungsfall. Ich habe 2 int-Variablen und möchte überprüfen, ob 2 Variablen im gleichen Bereich liegen wie (10-20), (20-30), .... wie
folgt
5

Oder Sie können Ihre Solofälle wie beabsichtigt verwenden und Ihren Standardfall verwenden, um Bereichsanweisungen wie folgt anzugeben:

switch(n) {
    case 1 : System.out.println("case 1"); break;
    case 4 : System.out.println("case 4"); break;
    case 99 : System.out.println("case 99"); break;
    default :
        if (n >= 10 && n <= 15)
            System.out.println("10-15 range"); 
        else if (n >= 100 && n <= 200)
            System.out.println("100-200 range");
        else
            System.out.println("Your default case");
        break;   
}
Xalamadrax
quelle
Dies ist, was ich immer mache, aber auch einen Kommentar zwischen den Fällen hinzufügen, zB: // 10 - 15 siehe unten Standard
Perdi Estaquel
4

Nein, das kannst du nicht. Das Beste, was Sie tun können, ist das

case 1:
case 2:
case 3:
case 4:
case 5: 
  System.Out.Println("testing case 1 to 5");
break;
FSP
quelle
3

Es ist möglich, mehrere Bedingungen in derselben caseAnweisung zu gruppieren, indem der durch switch-Anweisungen zulässige Fall-Through- Mechanismus verwendet wird. Dies wird im Java-Lernprogramm erwähnt und in Abschnitt §14.11 vollständig angegeben . Die switch-Anweisung der Java-Sprachspezifikation .

Der folgende Codeausschnitt stammt aus einem Beispiel im Lernprogramm und berechnet die Anzahl der Tage in jedem Monat (nummeriert von Monat 1 bis Monat 12):

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

Wie Sie sehen, besteht casedie einzige Alternative zum Abdecken eines Wertebereichs in einer einzelnen Anweisung darin, jeden der möglichen Werte einzeln nacheinander aufzulisten. Als zusätzliches Beispiel erfahren Sie, wie Sie den Pseudocode in der Frage implementieren:

switch(num) {
    case 1: case 2: case 3: case 4: case 5:
        System.out.println("testing case 1 to 5");
        break;
    case 6: case 7: case 8: case 9: case 10:
        System.out.println("testing case 6 to 10");
        break;
}
Óscar López
quelle
2

Sie können ein verwenden enum, um Ihre Bereiche darzustellen.

public static enum IntRange {
  ONE_TO_FIVE, SIX_TO_TEN;
  public boolean isInRange(int v) {
    switch (this) {
    case ONE_TO_FIVE:
      return (v >= 1 && v <= 5);
    case SIX_TO_TEN:
      return (v >= 6 && v <= 10);
    }
    return false;
  }

  public static IntRange getValue(int v) {
    if (v >= 1 && v <= 5) {
      return ONE_TO_FIVE;
    } else if (v >= 6 && v <= 10) {
      return SIX_TO_TEN;
    }
    return null;
  }
}
Elliott Frisch
quelle
2

Hier ist ein schöner und minimalistischer Weg

(num > 1 && num < 5) ? first_case_method() 
                     : System.out.println("testing case 1 to 5")
                     : (num > 5 && num < 7)  ? System.out.println("testing case 1 to 5") 
                     : (num > 7 && num < 8)  ? System.out.println("testing case 1 to 5") 
                     : (num > 8 && num < 9)  ? System.out.println("testing case 1 to 5") 
                     : ... 
                     : System.out.println("default");
Williem
quelle
Kannst du das erklären? - Ich bekomme die 'Mini Ifs', aber anders als dieser Idk.
Kamin Pallaghy
@Tunaki Dies ist eine if..elseifAlternative, bei der der ternäre Operator ( condition ? statementIfTrue : statementIfFalse) in Kaskade verwendet wird .
Williem
2

Verwenden Sie eine NavigableMapImplementierung wie TreeMap.

/* Setup */
NavigableMap<Integer, Optional<String>> messages = new TreeMap<>();
messages.put(Integer.MIN_VALUE, Optional.empty());
messages.put(1, Optional.of("testing case 1 to 5"));
messages.put(6, Optional.of("testing case 6 to 10"));
messages.put(11, Optional.empty());

/* Use */
messages.floorEntry(3).getValue().ifPresent(System.out::println);
erickson
quelle
Hervorragende Lösung! Vergessen Sie nicht, mit auf Null zu prüfen, if (messages.floorEntry(value)!=null) wenn Sie einen ganzzahligen Wert verwenden
Ch Vas
1
@ChVas Die Art und Weise, wie die Karte hier eingerichtet ist, floorEntry()wird niemals zurückkehren null(das Einfügen des Integer.MIN_VALUESchlüssels soll dies verhindern). Unabhängig von Ihrem Wertetyp müssen Sie jedoch entscheiden, wie Schlüssel außerhalb des gültigen Bereichs behandelt werden sollen.
Erickson
2

Es wird ab Java 12 unterstützt. Lesen Sie JEP 354 . Keine "Range" -Möglichkeiten hier, kann aber auch nützlich sein.

switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);//number of letters
    case TUESDAY                -> System.out.println(7);
    case THURSDAY, SATURDAY     -> System.out.println(8);
    case WEDNESDAY              -> System.out.println(9);
}

Sie sollten dies auch auf Ints implementieren können. Beachten Sie, dass Ihre switch-Anweisung vollständig sein muss (mit dem defaultSchlüsselwort oder mit allen möglichen Werten in case-Anweisungen).

A_Arnold
quelle
1

Die Antwort von @missingfaktor ist zwar richtig, aber etwas zu kompliziert. Code ist ausführlicher (zumindest für kontinuierliche Intervalle) als er sein könnte und erfordert Überladungen / Casts und / oder Parametrisierung für Long, Float, Integer usw.

if (num < 1)
    System.Out.Println("invalid case: " + num); // you should verify that anyway
else if (num <= 5)
    System.Out.Println("1 to 5");
else if (num <= 10)
    System.Out.Println("6 to 10");
else if (num <= 42)
    System.Out.Println("11 to 42");
else    
    System.Out.Println("43 to +infinity");
Alexander Malakhov
quelle
3
Entschuldigung für die verspätete Antwort, ich kann in letzter Zeit nicht mit SO-Antworten Schritt halten. Ich werde nacheinander auf Ihre Kritik antworten. 1. Code ist etwas ausführlicher, ja, und er führt auch redundante Berechnungen durch. Aber diese IMO trägt in diesem Fall zur Klarheit bei. In Ihrem Code muss man sich an die vorherigen Fälle erinnern, wenn man durch die Leiter fällt.
Fehlender Faktor
2
Das Erfordernis von Überladungen und Abgüssen ist IMO keine gültige Kritik. Dass Java keine sinnvolle Möglichkeit hat, über numerische Typen zu abstrahieren, sagt mehr über Javas Einschränkungen als über diesen Ansatz aus. Vielleicht möchten Sie Haskells NumTypklasse erkunden, wenn Sie diesen Punkt besser verstehen möchten.
Fehlender Faktor
@missingfaktor 1. Ich denke, das ist Geschmackssache. Wenn ifich mich mit kontinuierlichen Intervallen beschäftige, denke ich persönlich gerne an s, als würde ich allmählich den unteren Teilbereich verschütten. Darüber hinaus ist eine redundante Berechnung überhaupt kein Problem, aber ein redundanter Vergleich ist etwas besorgniserregend: Es wird einfacher, benachbarte Vergleiche nicht synchron zu machen, z. B. nach einigen Änderungen : if (isBetween(x, 1, 4)) {...} else if (isBetween(x, 6, 10)). Jedenfalls keine große Sache.
Alexander Malakhov
2. Einverstanden - Javas Einschränkung, aber damit müssen wir arbeiten, und Ihr Originalcode wird für verschiedene Typen dupliziert. In diesem speziellen Fall kann ein Problem durch die Verwendung der Number- Klasse gemildert werden , obwohl Haskells Ansatz besser ist (ich habe Haskell nie wirklich gelernt, aber er ähnelt "Concepts Light" von C ++. Ich glaube auch, dass Sie das gemeint haben Real, nicht Num).
Alexander Malakhov
0

Für Eingangsnummer im Bereich 0..100

int n1 = 75; // input value
String res; int n=0; 
int[] a ={0,20,35,55,70,85,101};

for(; n1>=a[n]; n++);
switch(6-n+1) {
  case 1: res="A"; break;
  case 2: res="B"; break;
  case 3: res="C"; break;
  case 4: res="D"; break;
  case 5: res="E"; break;
  default:res="F";
}
System.out.println(res);
Zemiak
quelle
0

Diese Art von Verhalten wird in Java nicht unterstützt. Wenn Sie jedoch ein großes Projekt haben, das dies benötigt, sollten Sie Groovy-Code in Ihr Projekt einblenden. Groovy-Code wird in Byte-Code kompiliert und kann mit JVM ausgeführt werden. Die Firma, für die ich arbeite, verwendet Groovy, um Serviceklassen zu schreiben, und Java, um alles andere zu schreiben.

Isoplayer
quelle