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)