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!

Image of AssemblyAI tool

Transforming Interviews into Publishable Stories with AssemblyAI

Insightview is a modern web application that streamlines the interview workflow for journalists. By leveraging AssemblyAI's LeMUR and Universal-2 technology, it transforms raw interview recordings into structured, actionable content, dramatically reducing the time from recording to publication.

Key Features:
🎥 Audio/video file upload with real-time preview
🗣️ Advanced transcription with speaker identification
⭐ Automatic highlight extraction of key moments
✍️ AI-powered article draft generation
📤 Export interview's subtitles in VTT format

Read full post

Top comments (0)

Image of AssemblyAI

Automatic Speech Recognition with AssemblyAI

Experience near-human accuracy, low-latency performance, and advanced Speech AI capabilities with AssemblyAI's Speech-to-Text API. Sign up today and get $50 in API credit. No credit card required.

Try the API

👋 Kindness is contagious

Discover a treasure trove of wisdom within this insightful piece, highly respected in the nurturing DEV Community enviroment. Developers, whether novice or expert, are encouraged to participate and add to our shared knowledge basin.

A simple "thank you" can illuminate someone's day. Express your appreciation in the comments section!

On DEV, sharing ideas smoothens our journey and strengthens our community ties. Learn something useful? Offering a quick thanks to the author is deeply appreciated.

Okay