Operador OR en caja de interruptores?

6 minutos de lectura

Avatar de usuario de Droidman
hombredroide

Tomemos un caso de interruptor simple que se parece a:

@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.someValue :
        case R.id.someOtherValue:
            // do stuff
            break;
    }
}

Me pregunto por qué no está permitido usar el || ¿operador? Me gusta

switch (v.getId()) {
    case R.id.someValue || R.id.someOtherValue:
        // do stuff
        break;
}

los switch-case construcción es bastante similar a un if-else instrucción, puede utilizar el operador OR en una if sin embargo. ¿Cuáles son los antecedentes para un switch-case para no aceptar este operador?

  • @OliCharlesworth sí. Revisa mi comentario para ver la respuesta de arshajii.

    – Droideman

    23 de agosto de 2013 a las 22:45

  • arshajii no parece tener una respuesta…

    –Dennis Meng

    23 de agosto de 2013 a las 22:46

  • || es esencialmente la operación predeterminada de una declaración de caso en ausencia de break.

    – Trevor Freeman

    23/08/2013 a las 22:50

  • Piénselo de esta manera: si Switch tuviera la misma capacidad que if-else, ¿por qué necesitamos ambos? ¡¡Será redundante!! La idea de cambiar es mejorar la legibilidad en lugar de escribir código espagueti con múltiples bloques if else. Podría decirse que el interruptor también ofrece un rendimiento ligeramente mejor debido a su simplicidad.

    – Serotonin Chase

    23 de agosto de 2013 a las 22:54

  • El idioma Ada hace exactamente el tipo de cosas que estás preguntando: dirías when Some_Value | Some_Other_Value => en un case declaración. Pero el lenguaje no usa | como operador, por lo que no hay forma de que esta sintaxis sea ambigua. Usando || para este propósito en C (Java, etc.) haría que la sintaxis fuera ambigua, y no es una buena idea tener reglas raras con excepciones (como || significa una cosa en una expresión excepto que significa algo diferente en un contexto diferente. ..).

    – ajb

    23 de agosto de 2013 a las 23:28

amigo haz esto

    case R.id.someValue :
    case R.id.someOtherValue :
       //do stuff

Esto es lo mismo que usar el operador OR entre dos valores. Debido a este caso, el operador no está allí en el cambio de caso.

  • Hola, @BalusC, esta respuesta realmente me ayudó con mi solicitud, por lo que sugiero mantener esta “respuesta”.

    – vaso de

    20 de marzo de 2019 a las 18:44

  • Fantástica solución.

    – Stephan Bakkelund Valois

    7 de noviembre de 2020 a las 16:43

Avatar de usuario de Rohit Jain
Rohit jainista

¿Cuáles son los antecedentes para que un switch-case no acepte este operador?

Porque case requiere expresión constante como su valor. Y desde un || expresión no es una constante de tiempo de compilación, no está permitida.

De JLS Sección 14.11:

La etiqueta del interruptor debe tener la siguiente sintaxis:

Cambiar etiqueta:
caso ExpresiónConstante:
caso EnumConstantName:
defecto :


Bajo el capó:

La razón detrás de permitir sólo la expresión constante con los casos se puede entender a partir de la JVM Spec Sección 3.10 – Compilación de conmutadores:

La compilación de sentencias switch utiliza el interruptor de mesa y cambio de búsqueda instrucciones. La instrucción tableswitch se usa cuando los casos del cambio pueden representarse eficientemente como índices en una tabla de compensaciones objetivo. El objetivo predeterminado del cambio se usa si el valor de la expresión del cambio cae fuera del rango de índices válidos.

Entonces, para que la etiqueta de casos sea utilizada por tableswitch como un índice en la tabla de compensaciones de destino, el valor del caso debe conocerse en el momento de la compilación. Eso solo es posible si el valor del caso es una expresión constante. Y || expresión se evaluará en tiempo de ejecución y el valor solo estará disponible en ese momento.

Desde la misma sección de JVM, lo siguiente switch-case:

switch (i) {
    case 0:  return  0;
    case 1:  return  1;
    case 2:  return  2;
    default: return -1;
}

se compila a:

0   iload_1             // Push local variable 1 (argument i)
1   tableswitch 0 to 2: // Valid indices are 0 through 2  (NOTICE This instruction?)
      0: 28             // If i is 0, continue at 28
      1: 30             // If i is 1, continue at 30
      2: 32             // If i is 2, continue at 32
      default:34        // Otherwise, continue at 34
28  iconst_0            // i was 0; push int constant 0...
29  ireturn             // ...and return it
30  iconst_1            // i was 1; push int constant 1...
31  ireturn             // ...and return it
32  iconst_2            // i was 2; push int constant 2...
33  ireturn             // ...and return it
34  iconst_m1           // otherwise push int constant -1...
35  ireturn             // ...and return it

Entonces, si el case el valor no es una expresión constante, el compilador no podrá indexarlo en la tabla de punteros de instrucción, usando tableswitch instrucción.

  • Tengo la sensación de que el autor de la pregunta lo sabe, pero se pregunta por qué se aplica esta restricción para empezar.

    – Adam Spurgin

    23 de agosto de 2013 a las 22:45

  • @ Maver1ck Probablemente porque no es necesario, ya que solo puede usar el fall-through. Aunque, esto está permitido (y llevado al extremo absurdo) en Scala.

    – arshajii

    23 de agosto de 2013 a las 22:47


  • @ Maver1ck Podría ser útil modificar la pregunta para indicar que sabe cómo se supone que debe hacerlo dentro de la sintaxis dada, pero se pregunta por qué esta no es una alternativa aceptable

    –Dennis Meng

    23 de agosto de 2013 a las 22:47


  • @ Maver1ck “dado que una expresión no es una constante de tiempo de compilación, no está permitida”. debido a esto, puede ejecutarse más rápido a través de una optimización del compilador más sencilla en muchos casos. Es más rápido que si las declaraciones debido a los trucos y la magia de bajo nivel.

    – progrenhard

    23 de agosto de 2013 a las 22:48


  • @ Maver1ck: También vale la pena señalar que R.id.foo || R.id.bar no significa nada, en ningún contexto (asumiendo foo y bar no son boolean).

    –Oliver Charlesworth

    23 de agosto de 2013 a las 23:08

Avatar de usuario de Hilaj
Hilaj

No puedes usar || operadores entre 2 casos. Pero puede usar múltiples valores de caso sin usar un descanso entre ellos. El programa luego saltará al caso respectivo y luego buscará código para ejecutar hasta que encuentre un “descanso”. Como resultado, estos casos compartirán el mismo código.

switch(value) 
{ 
    case 0: 
    case 1: 
        // do stuff for if case 0 || case 1 
        break; 
    // other cases 
    default: 
        break; 
}

  • Nunca lo había pensado así, interesante forma de hacerlo.

    – serraosays

    11 de abril de 2019 a las 3:18

  • O también puede usar así, caso 0, 1: //si el caso 0 || 1

    – Hilaj

    29 de mayo de 2019 a las 10:46


  • Esta debería ser la respuesta correcta. incluso el estudio de Android mostrará una sugerencia para fusionarse con una rama duplicada

    – Libín Thomas

    20 de septiembre de 2019 a las 9:34

  • Java 14 tiene una nueva declaración de cambio con sintaxis como case 0, 1 -> ... que puede evaluar una expresión, ejecutar un bloque de código o lanzar.

    – usuario904963

    24 de noviembre de 2021 a las 22:17

No sé cuál es el mejor enfoque, pero lo hago como

case 'E':
case 'e':
   System.exit(0);
   break;

Switch no es lo mismo que if-else-if.

El cambio se usa cuando hay una expresión que se evalúa como un valor y ese valor puede ser uno de un conjunto de valores predefinido. Si necesita realizar múltiples operaciones booleanas/comparaciones en tiempo de ejecución, entonces debe usar if-else-if.

Avatar de usuario de Dave Lee
dave lee

Todavía puedes hacerlo así.

switch (v.getId()) {
    case R.id.someValue: case R.id.someOtherValue:
        // do stuff
        break;
}

Avatar de usuario de Breimer
Breimer

foreach (array('one', 'two', 'three') as $v) {
    switch ($v) {
        case (function ($v) {
            if ($v == 'two') return $v;
            return 'one';
        })($v):
            echo "$v min \n";
            break;


    }
}

esto funciona bien para idiomas que admiten gabinetes

¿Ha sido útil esta solución?