Imagine que você está em uma bifurcação, como um herói de uma pintura famosa. Se você for para a esquerda, perderá seu cavalo; se for para a direita, ganhará conhecimento. Como programar tal situação? Você provavelmente já sabe que fazemos essa escolha usando construções if-then e if-then-else .
Apesar dos novos recursos, a abordagem usando enum é mais flexível e é recomendada para uso: podemos reutilizar esse enum muitas vezes.
if (turn_left) {
System.out.println(«Коня потеряешь»);
}
if (turn_right) {
System.out.println(“Знания обретёшь”);
}
else
System.out.println(“Так и будешь стоять?”);
E se não houver duas dessas faixas, mas 10? Existe um caminho “para a direita”, “um pouco para a esquerda”, “um pouco mais para a esquerda” e assim por diante, no valor de 10 peças? Imagine como o seu código if-then-else crescerá nesta versão!
if (вариант1)
{… }
else if (вариант2)
{…}
…
else if (вариантN) ….
Então, você não tem uma bifurcação de condições, mas várias, digamos, 10 (o importante aqui é que o número de bifurcações é limitado). Para tais situações, existe um operador de seleção especial - switch case java .
switch (ВыражениеДляВыбора) {
case (Значение1):
Код1;
break;
case (Значение2):
Код2;
break;
...
case (ЗначениеN):
КодN;
break;
default:
КодВыбораПоУмолчанию;
break;
}
A ordem de execução na instrução é a seguinte:
- A SelectionExpression é avaliada. A seguir, a instrução switch compara a expressão resultante com o próximo valor (na ordem listada).
- Se SelectExpression corresponder ao Valor, o código após os dois pontos será executado.
- Se a construção break for encontrada , o controle será transferido para fora do comando switch.
- Se nenhuma correspondência entre ExpressionForSelection e Values for encontrada, o controle será transferido para DefaultSelectionCode.
-
O tipo SelectionExpression para uma instrução de seleção switch em Java deve ser um dos seguintes:
- byte , curto , char , int .
- Seus wrappers são Byte , Short , Character , Integer .
- String (desde Java 7).
- Enumeração ( Enum ).
- O bloco padrão é opcional, então se SelectionExpression e Values não corresponderem, nenhuma ação será executada.
- break é opcional; se não estiver presente, o código continuará em execução (ignorando futuras comparações de valores em blocos case) até a primeira
break
instrução switch encontrada ou até o final. - se for necessário executar o mesmo código para várias opções de seleção, para evitar duplicação indicamos vários valores correspondentes na frente dele em blocos de casos consecutivos .
Vamos passar para a prática de usar a instrução switch em Java
Não se preocupe, terminamos a teoria e depois de mais exemplos tudo ficará muito mais claro. Então vamos começar. Vejamos um exemplo da astronomia sobre os planetas do sistema solar. De acordo com os mais recentes regulamentos internacionais, excluiremos Plutão (devido às propriedades da sua órbita). Lembremos que nossos planetas estão localizados a partir do Sol na seguinte sequência: Mercúrio, Vênus, Terra, Marte, Júpiter, Saturno, Urano e Netuno. Vamos criar um método Java que receba como entrada o número de série do planeta (relativo à distância do Sol), e como saída produza a composição principal da atmosfera deste planeta na forma de uma List <String> . Deixe-me lembrá-lo de que alguns planetas têm uma composição atmosférica semelhante. Assim, Vênus e Marte contêm principalmente dióxido de carbono, Júpiter e Saturno consistem em hidrogênio e hélio, e Urano e Netuno, além do último par de gases, também possuem metano. Nossa função:public static List<String> getPlanetAtmosphere(int seqNumberFromSun) {
List<String> result = new ArrayList<>();
switch (seqNumberFromSun) {
case 1: result.add("No Atmosphere");
break;
case 2:
case 4: result.add("Carbon dioxide");
break;
case 3: result.add("Carbon dioxide");
result.add("Nitrogen");
result.add("Oxygen");
break;
case 5:
case 6: result.add("Hydrogen");
result.add("Helium");
break;
case 7:
case 8: result.add("Methane");
result.add("Hydrogen");
result.add("Helium");
break;
default:
break;
}
return result;
}
Observação: comparamos o mesmo código com planetas com composições atmosféricas idênticas. E fizemos isso usando construções de casos consecutivos . Então, se quisermos obter a composição da atmosfera do nosso planeta natal, chamamos nosso método com parâmetro 3:
getPlanetAtmosphere(3).
System.out.println(getPlanetAtmosphere(3)) вернет нам [Углекислый газ, Азот, Кислород].
Experimente o break O que acontece se removermos todas as instruções break ? Vamos tentar na prática:
public static List<String> getPlanetAtmosphere(int seqNumberFromSun) {
List<String> result = new ArrayList<>();
switch (seqNumberFromSun) {
case 1: result.add("No Atmosphere");
case 2:
case 4: result.add("Carbon dioxide");
case 3: result.add("Carbon dioxide");
result.add("Nitrogen");
result.add("Oxygen");
case 5:
case 6: result.add("Hydrogen");
result.add("Helium");
case 7:
case 8: result.add("Methane");
result.add("Hydrogen");
result.add("Helium");
default:
}
return result;
}
Se imprimirmos o resultado do método System.out.println(getPlanetAtmosphere(3))
, nosso planeta natal não será tão adequado para a vida. Ou adequado? Julgue por si mesmo: [Dióxido de carbono, Nitrogênio, Oxigênio, Hidrogênio, Hélio, Metano, Hidrogênio, Hélio], Por que isso aconteceu? O programa executou todos os casos após a primeira partida e até o final do bloco switch.
Quebra excessiva de otimização
Observe que podemos melhorar o método com um arranjo diferente de diretivas de interrupção e opções de seleçãopublic static List<String> getPlanetAtmosphere(int seqNumberFromSun) {
List<String> result = new ArrayList<>();
switch (seqNumberFromSun) {
case 1: result.add("No Atmosphere");
break;
case 3: result.add("Nitrogen");
result.add("Oxygen");
case 2:
case 4: result.add("Carbon dioxide");
break;
case 7:
case 8: result.add("Methane");
case 5:
case 6: result.add("Hydrogen");
result.add("Helium");
}
return result;
}
Parece mais curto, não é? Reduzimos o número total de declarações brincando com a ordem e o reagrupamento dos casos . Agora cada tipo de gás é adicionado à lista em apenas uma linha de código. A listagem do último exemplo do método é mostrada apenas para demonstrar o trabalho; não é altamente recomendável escrever nesse estilo. Se o autor (e ainda mais os programadores terceirizados) de um código semelhante tiver que mantê-lo, será muito difícil restaurar a lógica para a formação de blocos de seleção e o código executável para a instrução java switch.
Diferenças de se
Embora as instruções if e switch sejam semelhantes em aparência , não esqueça que o operador de múltipla escolha switch baseia a escolha das opções de execução em um VALOR ESPECÍFICO, enquanto em if. pode ser qualquer expressão lógica. Leve esse fato em consideração ao projetar seu código. Vamos dar uma olhada mais de perto nas inovações para switch em diferentes versões do Java.Mudar no Java 7
Antes do Java 7, as primitivas byte, short, char e int podiam ser usadas como valor para um switch. Também havia suporte para enum e wrappers dos tipos primitivos listados acima: Character, Byte, Short e Integer. Mas muitas vezes precisamos encontrar o valor de uma string de switch java! Seria assim no Java 6:DayOfWeek day = DayOfWeek.fromValue("Thursday");
switch (day) {
case MONDAY:
System.out.println("Today is windy !");
break;
case THURSDAY:
System.out.println("Today is sunny !");
break;
case WEDNESDAY:
System.out.println("Today is rainy!");
break;
default:
System.out.println("Oooops, something wrong !");
E enum:
public enum DayOfWeek {
MONDAY("Monday"),
THURSDAY("Thursday"),
WEDNESDAY("Wednesday"),
NOT_FOUND("Not found");
private final String value;
DayOfWeek(final String value) {
this.value = value;
}
public static DayOfWeek fromValue(String value) {
for (final DayOfWeek dayOfWeek : values()) {
if (dayOfWeek.value.equalsIgnoreCase(value)) {
return dayOfWeek;
}
}
return NOT_FOUND;
}
}
Mas a partir do Java 7, foi possível usar o tipo String como valor para um switch:
String day = "Thursday";
switch (day) {
case "Monday":
System.out.println("Today is windy !");
break;
case "Thursday":
System.out.println("Today is sunny !");
break;
case "Wednesday":
System.out.println("Today is rainy!");
break;
default:
System.out.println("Oooops, something wrong !");
}
Mudar no Java 12
Java 12 melhorou as expressões Switch para correspondência de padrões. Se usarmos Switch como no exemplo acima, para definir o valor de alguma variável, tivemos que calcular o valor e atribuí-lo à variável dada, e então usar break:int count = 2;
int value;
switch (count) {
case 1:
value = 12;
break;
case 2:
value = 32;
break;
case 3:
value = 52;
break;
default:
value = 0;
}
Mas graças aos recursos do Java 12, podemos reescrever esta expressão da seguinte forma:
int value = switch (count) {
case 1:
break 12;
case 2:
break 32;
case 3:
break 52;
default:
break 0;
};
Vamos repassar um pouco as mudanças:
-
Se anteriormente definimos um valor variável dentro de blocos case, já que a instrução switch em si não poderia retornar nada, agora temos essa oportunidade e retornamos o valor diretamente usando switch.
-
Anteriormente, não podíamos mais ter nada à direita do break, mas agora usamos isso como uma instrução return para retornar o valor do nosso switch. Os dois pontos marcam o ponto de entrada em um bloco de instruções. Ou seja, a partir desse ponto começa a execução de todo o código abaixo, mesmo quando outro rótulo for encontrado.
O resultado é uma transição ponta a ponta de marca para marca, também chamada de fall -through.
int count = 2;
int value = switch (count) {
case 1 -> 12;
case 2 -> 32;
case 3 -> 52;
default -> 0;
};
O código ficou muito mais simples, não é? E mais uma coisa: o operador lambda também pode servir como um análogo típico de dois pontos, após o qual há um bloco inteiro com algumas operações:
int count = 2;
int value = switch (count) {
case 1 -> {
//some computational operations...
break 12;
}
case 2 -> {
//some computational operations...
break 32;
}
case 3 -> {
//some computational operations...
break 52;
}
default -> {
//some computational operations...
break 0;
}
};
Bem, e se em alguns casos o valor de retorno for o mesmo? Acontece que na verdade temos os mesmos casos para alguns valores diferentes. Veja como isso pode ser reduzido usando novos recursos no Java 12:
int count = 2;
int value = switch (count) {
case 1, 3, 5 -> 12;
case 2, 4, 6 -> 52;
default -> 0;
};
Mudar no Java 13
No Java 13, a forma como um switch retorna um valor mudou. Se em java 12 escrevemos o valor de retorno após o break, que serviu de retorno para nós para o bloco switch, agora retornaremos o valor usando a palavra yield . Vamos olhar:int value = switch (count) {
case 1:
yield 12;
case 2:
yield 32;
case 3:
yield 52;
default:
yield 0;
};
Ao mesmo tempo, o código escrito em java 12 usando break para retornar não será compilado (( Break será usado, mas em situações em que não precisamos retornar nada.
Total
- Use a instrução case quando houver mais de duas ramificações para evitar sobrecarregar seu código com estruturas if.
- Não se esqueça de finalizar o bloco lógico de cada ramificação correspondente a um valor específico (bloco case) com uma chamada break .
- Além de alguns tipos primitivos, a instrução switch também pode usar os tipos Enum e String como expressões .
- Lembre-se do bloco padrão - use-o para lidar com valores de seleção não planejados.
- Para otimizar o desempenho, mova as ramificações do código com as escolhas mais comuns para o início do bloco switch.
- Não se deixe levar pela “otimização” removendo a quebra no final do bloco de seleção de caso - esse código é difícil de entender e, como resultado, difícil de manter durante seu desenvolvimento.
GO TO FULL VERSION