¿Utiliza una declaración de cambio con un rango de valor en cada caso?


92

En Java, ¿es posible escribir una declaración de cambio donde cada caso contenga más de un valor? Por ejemplo (aunque claramente el siguiente código no funcionará):

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

Creo que esto se puede hacer en Objective C, ¿hay algo similar en Java? ¿O debería usar declaraciones if, en su else iflugar?


Incluso hay extensiones en C simple que permiten esto.
arshajii

En ese caso, tal vez if/elsesea ​​una mejor solución.
Eric Wang

Respuestas:


98

Java no tiene nada de eso. ¿Por qué no hacer lo siguiente?

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

1
Esto funciona muy bien y es simple. Además, si desea seleccionar números que no están en el rango, todo lo que necesita es si (! IsBetween ..., buen trabajo.
a54studio

1
@missingfaktor He criticado un poco tu respuesta. Entonces, probablemente querrá responder algo. +1 aunque.
Alexander Malakhov

@MCEmperor, no edite mi respuesta con sus preferencias de formato personales. Esa no es una edición útil.
missingfaktor

@missingfaktor Lo siento. Pero esa edición fue aprobada hace mucho tiempo; Ni siquiera recordaba haber hecho eso.
MC Emperor

76

Lo más cerca que puede llegar a ese tipo de comportamiento con switchdeclaraciones es

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

Utilice ifdeclaraciones.


29

otra alternativa es usar la operación matemática dividiéndola, por ejemplo:

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

Pero, como puede ver, esto solo se puede usar cuando el rango es fijo en cada caso.


6
Esto funciona bien con códigos de estado http divididos por 100.
Stefan

13

No creo que puedas hacer eso en Java. Lo mejor es poner el código en el último caso del rango.

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

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

9

Sé que esta publicación es antigua, pero creo que esta respuesta merece un reconocimiento. No es necesario evitar la declaración de cambio. Esto se puede hacer en Java, pero a través de la instrucción switch, no los casos. Implica el uso de operadores ternarios.

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

1
¡Buena solución! Con Java 7 y versiones posteriores, también puede activar una cadena para que sus casos sean aún más autodocumentados, por ejemplo, switch ((1 <= num && num <= 5 ) ? "1 .. 5" : ...y luego case "1 .. 5":.
Daniel Widdis

@DanielWiddis: Sugeriría usar una enumeración en lugar de cadenas, para garantizar la coherencia.
nmatt

@nmatt Generalmente de acuerdo. Estaba intentando permitir el uso de la sintaxis de estilo "1 .. 5".
Daniel Widdis

2
@DanielWiddis: Ciertamente algo bueno; Yo nombraría las constantes de enumeración como FROM_1_TO_5. Por lo general, los rangos tienen cierto significado y, en ese caso, las constantes enum se pueden nombrar de acuerdo con el significado del rango.
nmatt

1
Creo que podemos estar de acuerdo en que cualquier opción es mejor que 0, 1 o 2.
Daniel Widdis

6

O puede usar sus casos individuales según lo previsto y usar su caso predeterminado para especificar instrucciones de rango como:

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

Esto es lo que siempre hago, pero también agrego un comentario entre casos, por ejemplo: // 10 - 15 ver abajo predeterminado
Perdi Estaquel

5

Intente esto si debe usar el interruptor.

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

¿Podrías darme una explicación también?
user1140237

El rango de la función devuelve algún valor de acuerdo con el argumento de entrada, por lo que la detección del "rango de valor" podría realizarse aquí, junto con la cláusula de cambio de caso.
zl9394

Esto funciona para mi caso de uso, tengo 2 variables int y quiero verificar si 2 variables están en el mismo rango como (10-20), (20-30), .... así
Sameer Kazi

Sugeriría usar una enumeración en lugar de valores int mágicos.
nmatt

4

No, no puedes hacer eso. Lo mejor que puedes hacer es eso

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

4

Aquí hay una manera hermosa y minimalista de hacerlo.

(num > 1 && num < 5) ? first_case_method() 
                     : System.out.println("testing case 1 to 5")
                     : (num > 5 && num < 7)  ? System.out.println("testing case 5 to 7") 
                     : (num > 7 && num < 8)  ? System.out.println("testing case 7 to 8") 
                     : (num > 8 && num < 9)  ? System.out.println("testing case 8 to 9") 
                     : ... 
                     : System.out.println("default");

¿¿Puede explicar esto?? - Tengo los 'mini ifs' pero aparte de ese idk.
Kamin Pallaghy

@Tunaki esta es una if..elseifalternativa que usa en cascada el operador ternario ( condition ? statementIfTrue : statementIfFalse).
Williem

3

Es posible agrupar varias condiciones en la misma casedeclaración utilizando el mecanismo de caída permitido por las declaraciones de cambio, se menciona en el tutorial de Java y se especifica completamente en la sección §14.11. La declaración de cambio de la especificación del lenguaje Java .

El siguiente fragmento de código se tomó de un ejemplo del tutorial, calcula el número de días de cada mes (numerados desde el mes 1 hasta el mes 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;
}

Como puede ver, para cubrir un rango de valores en una sola casedeclaración, la única alternativa es enumerar cada uno de los valores posibles individualmente, uno tras otro. Como ejemplo adicional, aquí se explica cómo implementar el pseudocódigo en la pregunta:

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

3

Puede utilizar un enumpara representar sus rangos,

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

3

Es compatible a partir de Java 12. Consulte JEP 354 . Aquí no hay posibilidades de "rango", pero tampoco puede ser útil.

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

También debería poder implementar eso en ints. Tenga en cuenta que su declaración de cambio debe ser exhaustiva (usando defaultpalabras clave o usando todos los valores posibles en declaraciones de casos).


2

La respuesta de @missingfaktor es correcta pero un poco complicada. El código es más detallado (al menos para intervalos continuos) de lo que podría ser, y requiere sobrecargas / conversiones y / o parametrización para long, float, Integer, etc.

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

3
Perdón por la respuesta tardía, no puedo seguir el ritmo de las respuestas SO últimamente. Responderé a tu crítica una por una. 1. El código es un poco más detallado, sí, y también hace algunos cálculos redundantes. Pero esa OMI está contribuyendo a la claridad en este caso. En su código, uno tiene que recordar los casos anteriores a medida que cae por la escalera.
missingfaktor

2
En cuanto a requerir sobrecargas y moldes, esa no es una crítica válida en mi opinión. Que Java no tiene una forma sensata de abstraer los tipos numéricos dice sobre las limitaciones de Java, más que sobre este enfoque. Es posible que desee explorar la Numclase de tipos de Haskell si desea comprender mejor este punto.
missingfaktor

@missingfaktor 1. Supongo que es cuestión de gustos. Cuando se trata de intervalos continuos, personalmente me gusta pensar en ifs como si estuviera derramando gradualmente un subrango inferior. Además, un cálculo redundante no es un problema en absoluto, pero la comparación redundante es un poco preocupante: se vuelve más fácil de hacer comparaciones adyacentes fuera de sincronización, por ejemplo, después de algún edición: if (isBetween(x, 1, 4)) {...} else if (isBetween(x, 6, 10)). De todos modos, no es gran cosa.
Alexander Malakhov

2. De acuerdo: la limitación de Java, pero eso es con lo que tenemos que trabajar y su código original se duplicará para varios tipos. En este caso particular, un problema se puede mitigar usando la clase Number , aunque el enfoque de Haskell es mejor (nunca llegué a aprender realmente Haskell, pero se parece a "Concepts Light" de C ++. Además, creo que quiso decir Real, no Num).
Alexander Malakhov

2

Utilice una NavigableMapimplementación, como 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);

Excelente solucion! no olvide verificar if (messages.floorEntry(value)!=null) si hay un valor nulo si usa un valor entero
Ch Vas

1
@ChVas La forma en que el mapa está configurado aquí, floorEntry()nunca regresará null(insertar la Integer.MIN_VALUEclave tiene la intención de evitarlo). Pero, independientemente de su tipo de valor, debe decidir cómo manejar las claves fuera del rango válido.
erickson

0

Para el número de entrada en el rango 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);

0

Este tipo de comportamiento no es compatible con Java. Sin embargo, si tiene un proyecto grande que necesita esto, considere mezclar código Groovy en su proyecto. El código Groovy se compila en código de bytes y se puede ejecutar con JVM. La empresa para la que trabajo usa Groovy para escribir clases de servicio y Java para escribir todo lo demás.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.