Respuestas:
A veces es útil tener varios casos asociados con el mismo bloque de código, como
case 'A':
case 'B':
case 'C':
doSomething();
break;
case 'D':
case 'E':
doSomethingElse();
break;
etc. Solo un ejemplo.
En mi experiencia, por lo general es de mal estilo "fallar" y ejecutar varios bloques de código para un caso, pero puede ser útil en algunas situaciones.
// Intentional fallthrough.
cuando omita un descanso. En mi opinión, no es tanto un mal estilo como "fácil olvidar una ruptura accidentalmente". PD: Por supuesto que no en casos simples como en la propia respuesta.
case
se apilan juntos de esa manera. Si hay un código entre ellos, entonces sí, probablemente el comentario sea merecido.
case
, así:, case 'A','B','C': doSomething(); case 'D','E': doSomethingElse();
sin necesidad de un descanso entre los casos. Pascal podría hacer eso: "La declaración del caso compara el valor de la expresión ordinal con cada selector, que puede ser una constante, un subrango o una lista de ellos separados por comas". ( wiki.freepascal.org/Case )
Históricamente , se debe a que case
esencialmente definía un label
, también conocido como el punto de destino de una goto
llamada. La declaración de cambio y sus casos asociados realmente representan una rama de múltiples vías con múltiples puntos de entrada potenciales en un flujo de código.
Dicho todo esto, se ha observado un número casi infinito de veces que break
casi siempre es el comportamiento predeterminado que preferiría tener al final de cada caso.
Java proviene de C y esa es la sintaxis de C.
Hay ocasiones en las que desea que varias declaraciones de casos solo tengan una ruta de ejecución. A continuación se muestra una muestra que le dirá cuántos días en un mes.
class SwitchDemo2 {
public static void main(String[] args) {
int month = 2;
int year = 2000;
int numDays = 0;
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;
}
System.out.println("Number of Days = " + numDays);
}
}
Creo que es un error. Como construcción de lenguaje, es tan fácil de tener break
como predeterminado y, en su lugar, tener una fallthrough
palabra clave. La mayor parte del código que he escrito y leído tiene un descanso después de cada caso.
continue <case name>
que permite especificar explícitamente con qué declaración de caso continuar;
case
dentro de la corriente switch
, esto simplemente se convierte en un goto
. ;-)
Puede hacer todo tipo de cosas interesantes con la caída de casos.
Por ejemplo, digamos que desea realizar una acción en particular para todos los casos, pero en un caso determinado desea realizar esa acción y algo más. Usar una declaración de cambio con fallos lo haría bastante fácil.
switch (someValue)
{
case extendedActionValue:
// do extended action here, falls through to normal action
case normalActionValue:
case otherNormalActionValue:
// do normal action here
break;
}
Por supuesto, es fácil olvidar la break
declaración al final de un caso y provocar un comportamiento inesperado. Los buenos compiladores le advertirán cuando omita la declaración break.
¿Por qué el compilador no coloca automáticamente declaraciones break después de cada bloque de código en el conmutador?
Dejando a un lado las buenas ganas de poder utilizar el mismo bloque para varios casos (que podrían ser de carcasa especial) ...
¿Es por razones históricas? ¿Cuándo desea que se ejecuten varios bloques de código?
Es principalmente por compatibilidad con C, y podría decirse que es un antiguo truco de los días de antaño cuando las goto
palabras clave vagaban por la tierra. Se hace servir para que algunas cosas increíbles, por supuesto, como el dispositivo de Duff , pero si eso es un punto a su favor o en contra ... es argumentativo en el mejor.
El break
after switch case
s se usa para evitar errores en las declaraciones de switch. Aunque es interesante, esto ahora se puede lograr a través de las etiquetas de interruptor recién formadas implementadas a través de JEP-325 .
Con estos cambios, el break
con cada interruptor case
se puede evitar como se demuestra más adelante: -
public class SwitchExpressionsNoFallThrough {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int value = scanner.nextInt();
/*
* Before JEP-325
*/
switch (value) {
case 1:
System.out.println("one");
case 2:
System.out.println("two");
default:
System.out.println("many");
}
/*
* After JEP-325
*/
switch (value) {
case 1 ->System.out.println("one");
case 2 ->System.out.println("two");
default ->System.out.println("many");
}
}
}
En ejecutar el código anterior con JDK-12 , la salida comparativa podría verse como
//input
1
// output from the implementation before JEP-325
one
two
many
// output from the implementation after JEP-325
one
y
//input
2
// output from the implementation before JEP-325
two
many
// output from the implementation after JEP-325
two
y por supuesto la cosa sin cambios
// input
3
many // default case match
many // branches to 'default' as well
Por lo tanto, no tiene que repetir el código si necesita varios casos para hacer lo mismo:
case THIS:
case THAT:
{
code;
break;
}
O puedes hacer cosas como:
case THIS:
{
do this;
}
case THAT:
{
do that;
}
En forma de cascada.
Realmente propenso a errores / confusión, si me preguntas.
do this
como do that
para eso, pero solo do that
para eso?
En lo que respecta al registro histórico, Tony Hoare inventó el enunciado del caso en la década de 1960, durante la revolución de la "programación estructurada". La declaración de caso de Tony admitía múltiples etiquetas por caso y salida automática sin break
declaraciones apestosas . El requisito de un explícito break
fue algo que salió de la línea BCPL / B / C. Dennis Ritchie escribe (en ACM HOPL-II):
Por ejemplo, el caso final que se escapa de una declaración de conmutación BCPL no estaba presente en el lenguaje cuando lo aprendimos en la década de 1960, por lo que la sobrecarga de la palabra clave break para escapar de la declaración de conmutación B y C se debe a la evolución divergente en lugar de a la conciencia. cambio.
No he podido encontrar ningún escrito histórico sobre BCPL, pero el comentario de Ritchie sugiere que break
fue más o menos un accidente histórico. BCPL luego solucionó el problema, pero quizás Ritchie y Thompson estaban demasiado ocupados inventando Unix para molestarse con tal detalle :-)
break
permite "ejecutar múltiples bloques de código", y está más preocupado por la motivación de esta elección de diseño. Otros mencionaron la herencia bien conocida de C a Java, y esta respuesta llevó la investigación aún más a los días anteriores a C. Ojalá tuviéramos esta coincidencia de patrones (aunque muy primitiva) desde el principio.
Java se deriva de C, cuya herencia incluye una técnica conocida como Dispositivo de Duff . Es una optimización que se basa en el hecho de que el control pasa de un caso a otro, en ausencia de una break;
declaración. Para cuando C se estandarizó, había mucho código como ese "en la naturaleza", y hubiera sido contraproducente cambiar el lenguaje para romper tales construcciones.
Como la gente dijo antes, es para permitir la caída y no es un error, es una característica. Si le break
molestan demasiadas declaraciones, puede deshacerse de ellas fácilmente utilizando return
declaraciones en su lugar. En realidad, esta es una buena práctica, porque sus métodos deben ser lo más pequeños posible (en aras de la legibilidad y el mantenimiento), por lo que una switch
declaración ya es lo suficientemente grande para un método, por lo tanto, un buen método no debe contener nada más, esto es un ejemplo:
public class SwitchTester{
private static final Log log = LogFactory.getLog(SwitchTester.class);
public static void main(String[] args){
log.info(monthsOfTheSeason(Season.WINTER));
log.info(monthsOfTheSeason(Season.SPRING));
log.info(monthsOfTheSeason(Season.SUMMER));
log.info(monthsOfTheSeason(Season.AUTUMN));
}
enum Season{WINTER, SPRING, SUMMER, AUTUMN};
static String monthsOfTheSeason(Season season){
switch(season){
case WINTER:
return "Dec, Jan, Feb";
case SPRING:
return "Mar, Apr, May";
case SUMMER:
return "Jun, Jul, Aug";
case AUTUMN:
return "Sep, Oct, Nov";
default:
//actually a NullPointerException will be thrown before reaching this
throw new IllegalArgumentException("Season must not be null");
}
}
}
La ejecución imprime:
12:37:25.760 [main] INFO lang.SwitchTester - Dec, Jan, Feb
12:37:25.762 [main] INFO lang.SwitchTester - Mar, Apr, May
12:37:25.762 [main] INFO lang.SwitchTester - Jun, Jul, Aug
12:37:25.762 [main] INFO lang.SwitchTester - Sep, Oct, Nov
como se esperaba.
No tener una interrupción automática agregada por el compilador hace posible usar un interruptor / caso para probar condiciones como 1 <= a <= 3
eliminar la declaración de interrupción de 1 y 2.
switch(a) {
case 1: //I'm between 1 and 3
case 2: //I'm between 1 and 3
case 3: //I'm between 1 and 3
break;
}
Es una vieja pregunta, pero en realidad me encontré usando el caso sin una declaración de interrupción hoy. En realidad, no utilizar break es muy útil cuando necesita combinar diferentes funciones en secuencia.
por ejemplo, usando códigos de respuesta http para autenticar al usuario con el token de tiempo
código de respuesta del servidor 401 - el token está desactualizado -> regenerar el token e iniciar la sesión del usuario.
código de respuesta del servidor 200 - el token está bien -> iniciar la sesión del usuario.
en declaraciones de casos:
case 404:
case 500:
{
Log.v("Server responses","Unable to respond due to server error");
break;
}
case 401:
{
//regenerate token
}
case 200:
{
// log in user
break;
}
Con esto, no es necesario llamar a la función de inicio de sesión de usuario para la respuesta 401 porque cuando se regenera el token, el tiempo de ejecución salta al caso 200.
Puede separar fácilmente otro tipo de número, mes, recuento.
Esto es mejor entonces si en este caso;
public static void spanishNumbers(String span){
span = span.toLowerCase().replace(" ", "");
switch (span){
case "1":
case "jan": System.out.println("uno"); break;
case "2":
case "feb": System.out.println("dos"); break;
case "3":
case "mar": System.out.println("tres"); break;
case "4":
case "apr": System.out.println("cuatro"); break;
case "5":
case "may": System.out.println("cinco"); break;
case "6":
case "jun": System.out.println("seis"); break;
case "7":
case "jul": System.out.println("seite"); break;
case "8":
case "aug": System.out.println("ocho"); break;
case "9":
case "sep": System.out.println("nueve"); break;
case "10":
case "oct": System.out.println("diez"); break;
}
}
Ahora estoy trabajando en un proyecto donde lo necesito break
en mi declaración de cambio, de lo contrario, el código no funcionará. Tenga paciencia conmigo y le daré un buen ejemplo de por qué lo necesita break
en su declaración de cambio.
Imagine que tiene tres estados, uno que espera a que el usuario ingrese un número, el segundo para calcularlo y el tercero para imprimir la suma.
En ese caso tienes:
Mirando los estados, querrá que el orden de exacción comience en state1 , luego state3 y finalmente state2 . De lo contrario, solo imprimiremos la entrada de los usuarios sin calcular la suma. Solo para aclararlo nuevamente, esperamos que el usuario ingrese un valor, luego calculamos la suma e imprime la suma.
Aquí hay un código de ejemplo:
while(1){
switch(state){
case state1:
// Wait for user input code
state = state3; // Jump to state3
break;
case state2:
//Print the sum code
state = state3; // Jump to state3;
case state3:
// Calculate the sum code
state = wait; // Jump to state1
break;
}
}
Si no lo usamos break
, se ejecutará en este orden, estado1 , estado2 y estado3 . Pero al usar break
, evitamos este escenario y podemos ordenar el procedimiento correcto que es comenzar con state1, luego state3 y por último, pero no menos importante, state2.
break
.