Respostas:
Às vezes é útil ter vários casos associados ao mesmo bloco de código, como
case 'A':
case 'B':
case 'C':
doSomething();
break;
case 'D':
case 'E':
doSomethingElse();
break;
etc. Apenas um exemplo.
Na minha experiência, geralmente é um estilo ruim "falhar" e ter vários blocos de código executados para um caso, mas pode haver usos para isso em algumas situações.
// Intentional fallthrough.
ao omitir uma pausa. Não é tanto um estilo ruim quanto "fácil de esquecer uma pausa acidentalmente" na minha opinião. PS Claro que não em casos simples como na própria resposta.
case
s estivessem empilhados dessa forma. Se houver código entre eles, então sim, o comentário provavelmente é válido.
case
, assim case 'A','B','C': doSomething(); case 'D','E': doSomethingElse();
:, sem precisar de uma pausa entre os casos. Pascal poderia fazer isso: "A instrução case compara o valor da expressão ordinal a cada seletor, que pode ser uma constante, um subintervalo ou uma lista deles separados por vírgulas." ( wiki.freepascal.org/Case )
Historicamente , é porque o case
estava essencialmente definindo um label
, também conhecido como o ponto-alvo de uma goto
chamada. A instrução switch e seus casos associados representam apenas uma ramificação de múltiplas vias com vários pontos de entrada potenciais em um fluxo de código.
Dito isso, foi observado um número quase infinito de vezes que break
quase sempre é o comportamento padrão que você prefere ter no final de cada caso.
Java vem de C e essa é a sintaxe de C.
Há momentos em que você deseja que várias instruções de caso tenham apenas um caminho de execução. Abaixo está um exemplo que dirá quantos dias em um mês.
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);
}
}
Eu acho que é um erro. Como uma construção de linguagem é tão fácil de ter break
quanto o padrão e, em vez disso, ter uma fallthrough
palavra - chave. A maior parte do código que escrevi e li tem uma pausa após cada caso.
continue <case name>
que permite especificar explicitamente com qual instrução de caso continuar;
case
dentro da corrente switch
, isso simplesmente se torna um goto
. ;-)
Você pode fazer todo tipo de coisa interessante com o caso de falha.
Por exemplo, digamos que você queira fazer uma ação específica para todos os casos, mas em um determinado caso você deseja fazer essa ação mais alguma outra coisa. Usar uma instrução switch com fall-through tornaria isso muito fácil.
switch (someValue)
{
case extendedActionValue:
// do extended action here, falls through to normal action
case normalActionValue:
case otherNormalActionValue:
// do normal action here
break;
}
Obviamente, é fácil esquecer a break
declaração no final de um caso e causar um comportamento inesperado. Bons compiladores irão avisá-lo quando você omitir a instrução break.
Por que o compilador não coloca automaticamente as instruções break após cada bloco de código no switch?
Deixando de lado a boa vontade de poder usar o bloco idêntico para vários casos (que poderiam ser especiais) ...
É por razões históricas? Quando você deseja que vários blocos de código sejam executados?
É principalmente para compatibilidade com C, e é indiscutivelmente um hack antigo dos tempos antigos, quando as goto
palavras-chave vagavam pela terra. Ele faz permitir que algumas coisas surpreendentes, é claro, como o dispositivo de Duff , mas se isso é um ponto a seu favor ou contra é ... argumentativa na melhor das hipóteses.
O break
switch posterior case
s é usado para evitar a queda nas instruções switch. Embora seja interessante, isso agora pode ser alcançado por meio dos rótulos de switch recém-formados, implementados via JEP-325 .
Com essas mudanças, o break
com cada troca case
pode ser evitado conforme demonstrado mais adiante: -
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");
}
}
}
Ao executar o código acima com JDK-12 , a saída comparativa pode ser vista como
//input
1
// output from the implementation before JEP-325
one
two
many
// output from the implementation after JEP-325
one
e
//input
2
// output from the implementation before JEP-325
two
many
// output from the implementation after JEP-325
two
e, claro, a coisa inalterada
// input
3
many // default case match
many // branches to 'default' as well
Portanto, você não precisa repetir o código se precisar de vários casos para fazer a mesma coisa:
case THIS:
case THAT:
{
code;
break;
}
Ou você pode fazer coisas como:
case THIS:
{
do this;
}
case THAT:
{
do that;
}
Em forma de cascata.
Muito sujeito a erros / confusão, se você me perguntar.
do this
e do that
para isso, mas apenas do that
para isso?
No que diz respeito ao registro histórico, Tony Hoare inventou a declaração do caso na década de 1960, durante a revolução da "programação estruturada". A declaração de caso de Tony suportava vários rótulos por caso e saída automática sem break
declarações fedorentas . A exigência de um explícito break
foi algo que saiu da linha BCPL / B / C. Dennis Ritchie escreve (em ACM HOPL-II):
Por exemplo, o endcase que escapa de uma instrução switchon BCPL não estava presente na linguagem quando a aprendemos na década de 1960 e, portanto, a sobrecarga da palavra-chave break para escapar da instrução switch B e C deve-se à evolução divergente em vez de consciente mudança.
Não consegui encontrar nenhum escrito histórico sobre a BCPL, mas o comentário de Ritchie sugere que break
foi mais ou menos um acidente histórico. O BCPL mais tarde corrigiu o problema, mas talvez Ritchie e Thompson estivessem ocupados demais inventando o Unix para se incomodar com tal detalhe :-)
break
permite "executar vários blocos de código", e está mais preocupado com a motivação dessa escolha de design. Outros mencionaram a herança bem conhecida do C ao Java, e essa resposta empurrou a pesquisa ainda mais para os dias anteriores ao C. Eu gostaria que tivéssemos esse padrão (embora muito primitivo) correspondendo desde o início.
Java é derivado de C, cuja herança inclui uma técnica conhecida como Dispositivo de Duff . É uma otimização que depende do fato de que o controle cai de um caso para o outro, na ausência de uma break;
instrução. Na época em que C foi padronizado, havia muito código como aquele "em liberdade", e teria sido contraproducente alterar a linguagem para quebrar tais construções.
Como já se disse antes, é para permitir falhas e não é um erro, é uma característica. Se muitas break
declarações o incomodam, você pode facilmente se livrar delas usando as return
declarações. Na verdade, esta é uma boa prática, porque seus métodos devem ser os menores possíveis (por uma questão de legibilidade e manutenção), então uma switch
instrução já é grande o suficiente para um método, portanto, um bom método não deve conter nada mais, isso é um exemplo:
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");
}
}
}
A execução 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 esperado.
Não ter uma interrupção automática adicionada pelo compilador torna possível usar uma opção / caso para testar as condições, como 1 <= a <= 3
remover a instrução break de 1 e 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;
}
É uma pergunta antiga, mas na verdade eu me deparei com a instrução case without break hoje. Na verdade, não usar break é muito útil quando você precisa combinar diferentes funções em sequência.
por exemplo, usando códigos de resposta http para autenticar o usuário com token de tempo
código de resposta do servidor 401 - token desatualizado -> regenerar token e fazer login do usuário.
código de resposta do servidor 200 - token está OK -> fazer login do usuário.
em declarações de caso:
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;
}
Usando isso, você não precisa chamar a função de usuário de log para a resposta 401 porque quando o token é regenerado, o tempo de execução pula para o caso 200.
Você pode fazer facilmente separar outro tipo de número, mês, contagem.
Isso é melhor do que neste 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;
}
}
Agora estou trabalhando em um projeto do qual preciso, break
em minha instrução switch, caso contrário, o código não funcionará. Tenha paciência comigo e eu darei um bom exemplo de por que você precisa break
em sua declaração switch.
Imagine que você tenha três estados, um que espera que o usuário insira um número, o segundo para calculá-lo e o terceiro para imprimir a soma.
Nesse caso, você tem:
Olhando para os estados, você gostaria que a ordem de exação começasse no estado1 , depois no estado3 e finalmente no estado2 . Caso contrário, imprimiremos apenas as entradas dos usuários sem calcular a soma. Só para esclarecer novamente, esperamos que o usuário insira um valor, então calculamos a soma e imprime a soma.
Aqui está um exemplo de código:
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;
}
}
Se não usarmos break
, ele será executado nesta ordem, estado1 , estado2 e estado3 . Mas usando break
, evitamos este cenário e podemos solicitar o procedimento correto que deve começar com o estado1, depois o estado3 e, por último, mas não menos importante, o estado2.
break
.