DEV Community

Cover image for "Pesquei, Java!": Transformações do Switch: Novidades e Recursos
Bárbara Salla
Bárbara Salla

Posted on

"Pesquei, Java!": Transformações do Switch: Novidades e Recursos

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+""); } 
Enter fullscreen mode Exit fullscreen mode

Resposta do console:

Image description

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+""); } 
Enter fullscreen mode Exit fullscreen mode

Resposta do console:

Image description

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."); } } 
Enter fullscreen mode Exit fullscreen mode

Resposta do console:

Image description

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); } 
Enter fullscreen mode Exit fullscreen mode

Resposta do console:

Image description

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; } 
Enter fullscreen mode Exit fullscreen mode

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"); } } 
Enter fullscreen mode Exit fullscreen mode

Resposta do console:

Image description

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"; }; } } 
Enter fullscreen mode Exit fullscreen mode

Erro de compilação:

Image description

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"; }; } } 
Enter fullscreen mode Exit fullscreen mode

Resposta do console:

Image description

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"; }; } } 
Enter fullscreen mode Exit fullscreen mode

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 o switch 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:

Image description

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"); } } 
Enter fullscreen mode Exit fullscreen mode

Resposta console:

Image description

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"); } } 
Enter fullscreen mode Exit fullscreen mode

Resposta console:

Image description

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"); 
Enter fullscreen mode Exit fullscreen mode

Espero que essas informações tenham sido úteis para você e agreguem ao seu código. Até mais!

Top comments (0)