O switch
no Java, desde quando surgiu, já passou por várias atualizações, tornando-se cada vez mais versátil e poderoso. Essas melhorias impactaram tanto o comportamento, sintaxe, exaustividade e a capacidade de trabalhar com diferentes tipos de dados.
Inicialmente, o switch
foi introduzido como uma declaração, e, mais tarde, evoluiu para incluir o conceito de expressão em versões mais recentes. Para entender melhor o que esses dois conceitos significam, podemos descreve-los como:
- Declaração: É usada para controlar o fluxo do programa, executando diferentes blocos de código com base no valor de uma variável. Não retorna diretamente um valor.
- Expressão: Avalia uma condição e retorna um valor diretamente, que pode ser atribuído a uma variável, por exemplo.
A seguir, exploraremos as mudanças ao longo das versões do Java e suas implicações práticas.
1.Switch como Declaração (Forma Clássica)
Quando falamos do switch
como declaração, estamos nos referindo à forma clássica de uso dessa estrutura. Em versões anteriores do Java, o switch
só era utilizado apenas como uma declaração básica de controle de fluxo. Ele podia ser usado com tipos int, char, byte, short e outros, mas sempre sem retornar um valor diretamente.
Limitações da forma clássica do switch:
- Tipos restritos: Apenas funcionava com tipos primitivos numéricos (int, short, char, byte) e, posteriormente, com String (a partir do Java 7) e enums (Java 5).
- Repetitividade: Não permitia a reutilização de lógica ou a utilização de blocos mais compactos.
- Inflexibilidade: Não suportava expressões complexas ou a possibilidade de retornar diretamente valores.
- Escalabilidade: O switch clássico era inadequado para cenários em que era necessário lidar com múltiplos tipos de dados ou condições compostas, como intervalos de valores.
Exemplo: Switch clássico com números inteiros
public static void main(String[] args) {
var dayValue = 1;
String day = "";
switch (dayValue){
case 1:
day = "sunday";
break;
case 2:
day = "monday";
break;
case 3:
day = "Tuesday";
break;
case 4:
day = "Wednesday";
break;
case 5:
day = "Thursday";
break;
case 6:
day = "Friday";
break;
case 7:
day = "Saturday";
break;
default:
System.out.println("Invalid Value: "+ dayValue);
}
System.out.println("\nValue: "+dayValue+"\nDay: "+ day+"");
}
Resposta do console:
Nesse cenário, por exemplo, se retirarmos o break, o programa executará todos os blocos a partir do caso correspondente ao valor, resultando no comportamento que conhecemos como "Fall Through".
public static void main(String[] args) {
var dayValue = 1;
String day = "";
switch (dayValue){
case 1:
day = "Sunday";
case 2:
day = "Monday";
case 3:
day = "Tuesday";
case 4:
day = "Wednesday";
case 5:
day = "Thursday";
case 6:
day = "Friday";
case 7:
day = "Saturday";
default:
System.out.println("Invalid Value: "+ dayValue);
}
System.out.println("\nValue: "+dayValue+"\nDay: "+ day+"");
}
Resposta do console:
2.Suporte a String no Switch (Java 7):
A partir do Java 7, podemos então passar valores do tipo String
como parâmetro no switch
, ampliando significativamente o seus casos de uso, por exemplo:
public static void main(String[] args) {
String day = "Monday";
switch (day) {
case "Monday":
System.out.println("Start of the work week.");
break;
case "Tuesday":
case "Wednesday":
case "Thursday":
System.out.println("Midweek days.");
break;
case "Friday":
System.out.println("Almost the weekend!");
break;
case "Saturday":
case "Sunday":
System.out.println("Weekend!");
break;
default:
System.out.println("Invalid day.");
}
}
Resposta do console:
3.Switch com Expressões (Java 12+):
O Java 12 introduziu as Switch Expressions (inicialmente como recurso preview). Com isso, o switch
ganhou uma nova sintaxe e a capacidade de permitir ao switch
retornar diretamente valores a uma variável, eliminando a necessidade de utilizar o break
. No exemplo a seguir, podemos observar a implementação direta do switch
após o sinal de atribuição de valor (=) da variável day
.
public static void main(String[] args) {
int dayValue = 6;
String day = switch (dayValue){
case 1 -> "Sunday";
case 2 -> "Monday";
case 3 -> "Tuesday";
case 4 -> "Wednesday";
case 5 -> "Thursday";
case 6 -> "Friday";
case 7 -> "Saturday";
default -> "invalid day.";
};
System.out.println("\nValue: "+dayValue+"\nDay: "+ day);
}
Resposta do console:
4.Uso do Yield (Java 13/14)
O yield
foi introduzido no Java 13 como parte das Switch Expressions, sendo apenas oficializado no Java 14. O termo yield
é usado para retornar um valor em bloco de código dentro do switch
. Tornando possível usar blocos de código mais complexos e retornar valores a partir deles.
public String getDayType(int day) {
String dayType = switch (day) {
case 1 -> "Monday";
case 2 -> "Tuesday";
case 3 -> "Wednesday";
default -> {
System.out.print("Invalid day");
yield null;
}
};
return dayType;
}
No exemplo acima, o yield
permite adicionar blocos de código em um case usando {}
e retornar valores específicos ao final do processamento, tornando possível implementar diferentes comportamentos para os diversos cases. Diferentemente do já conhecido return
, que sai e finaliza imediatamente a execução do método, o yield
apenas retorna um valor para a expressão switch
.
5.Múltiplos Valores por Case (Java 14)
Com o Java 14, as Switch Expressions foram formalizadas e, além disso, tornou-se possível combinar vários valores em um único case, simplificando condições que compartilham o mesmo comportamento, como no exemplo abaixo:
public static void main(String[] args) {
String day = "Monday";
switch (day) {
case "Saturday", "Sunday":
System.out.println("Weekend");
break;
case "Monday", "Tuesday", "Wednesday", "Thursday":
System.out.println("Weekday");
break;
default:
System.out.println("Invalid day");
}
}
Resposta do console:
6.Exaustividade no Switch (Java 12 e Java 14)
Com o switch
e as Switch Expressions, se os valores possíveis forem completamente definidos, como quando trabalhamos com Enum, o compilador pode verificar se todos os casos foram cobertos, garantindo maior controle e segurança na implementação. Assim, o compilador consegue interpretar se todas as opções foram tratadas nos cases
e sinalizar caso não esteja cobrindo todas as possibilidades, evitando comportamentos inesperados em tempo de execução.
Portanto, se todos os casos não forem cobertos, o compilador emitirá um erro de compilação, como mostrado no exemplo abaixo:
public class Main {
enum Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
public static void main(String[] args) {
Day day = Day.FRIDAY;
System.out.println("This day falls on a " + getDayType(day));
}
public static String getDayType(Day day) {
return switch (day) {
case MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY -> "Weekday";
case SATURDAY -> "Weekend";
};
}
}
Erro de compilação:
Já com todas as opções tratadas, o código compila e roda conforme esperado:
public class Main {
enum Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
public static void main(String[] args) {
Day day = Day.FRIDAY;
System.out.println("This day falls on a " + getDayType(day));
}
public static String getDayType(Day day) {
return switch (day) {
case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> "Weekday";
case SATURDAY, SUNDAY -> "Weekend";
};
}
}
Resposta do console:
7.Exaustividade no switch com Classes Seladas (Java 17)
A exaustividade no switch
também se aplica a classes seladas a partir do Java 17. Uma classe selada controla diretamente quais outras classes ou interfaces podem estendê-las ou implementá-las, limitando a hierarquia de herança, permitindo que o compilador verifique se todos os casos possíveis foram tratados.
sealed class Day permits Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday { }
final class Monday extends Day { }
final class Tuesday extends Day { }
final class Wednesday extends Day { }
final class Thursday extends Day { }
final class Friday extends Day { }
final class Saturday extends Day { }
final class Sunday extends Day { }
public class Main {
public static void main(String[] args) {
Day day = new Monday();
System.out.println("Today is: " + dayType(day));
}
public static String dayType(Day day) {
return switch (day) {
case Tuesday t -> "Weekday";
case Friday f -> "Weekday";
case Saturday s -> "Weekend";
};
}
}
Conforme o exemplo acima, verificamos que:
- Temos uma classe selada Day que permite apenas que as classe Monday, Tuesday, Wednesday, Thursday, Friday, Saturday e Sunday herdam seus atributos e comportamentos.
- Temos no método main a chamada de um método (
dayType()
) que utiliza oswitch
com classes seladas. - Não temos todas as opções de subclasses da Classe Day contempladas nos cases do
switch
, resultando num erro de compilação:
8.Pattern Matching no Switch (Java 17)
Outra novidade introduzida no Java 17 foi a integração do switch
ao recurso Pattern Matching, permitindo verificar se determinado objeto é do tipo de uma classe especifica a partir de um switch
.
Antes do Java 17, a verificação de tipos era feita com instanceof e exigia blocos separados de código, como no exemplo abaixo:
public static void main(String[] args) {
Object object = "text";
if(object instanceof String){
System.out.println("This object is a String");
} else if (object instanceof Long) {
System.out.println("This object is a long");
} else {
System.out.println("Unidentified object type");
}
}
Resposta console:
Já quando aplicamos o Pattern Matching com switch
temos a seguinte sintaxe:
public static void main(String[] args) {
Object object = "text";
switch (object){
case String s-> System.out.println("This object is a String");
case Integer i -> System.out.println("This object is a Integer");
default -> System.out.println("Unidentified object type");
}
}
Resposta console:
Esse recurso facilita a verificação de tipos, evitando a necessidade do instanceof e de blocos separados para diferentes tipos de objetos.
9.Uso de null como case (Java 17)
A partir do Java 17, tornou-se possível atribuir valor null
a um case
no switch, por exemplo:
case null -> System.out.println("This is a null object");
Espero que essas informações tenham sido úteis para você e agreguem ao seu código. Até mais!
Top comments (0)