Article image
Fernando Araujo
Fernando Araujo09/02/2024 16:48
Compartilhe

Funções em Java – as instruções switch-case (sim, no plural!)

  • #Java

Olá, dev!

 

Este artigo apresenta a instrução switch/case em Java, nas suas duas variações, em que situações cada um é aplicado e mostra exemplos de uso.

 

Sumário

1.   Introdução

2.  A instrução switch statement”

3.  A instrução switch expression”

4.   Considerações finais

5.   Referências

 

1 – Introdução

Normalmente, a execução de um programa de computador segue um fluxo sequencial, tanto para uma linguagem estruturada quanto dentro de um método de uma classe, em linguagens Orientadas a Objetos.

 

Este fluxo pode ser alterado por comandos de seleção, que testam uma condição e, dependendo do resultado, podem seguir executando instruções em vários caminhos alternativos.

 

Os comandos de seleção mais comuns, oferecidos por todas as linguagens de programação que eu conheço, são:

·        If: comando de seleção única;

·        If-else: comando de seleção dupla;

·        Switch-case: comando de seleção múltipla;

 

Este artigo apresenta a instrução switch-case em Java, lista as situações em que ele se aplica e mostra exemplos do seu uso.

           

Para entender melhor, veja a diferença básica na codificação de uma mesma situação de seleção múltipla, primeiro, usando a instrução if-else e, depois, com o uso da instrução switch-case tradicional.


image

 

O comando switch case é usado em lugar de vários comandos if-else aninhados, criando uma forma de seleção mais legível para o programador, bem como, de dar manutenção no código.


image

A linguagem Java provê dois tipos de comandos switch-case:

·        Declaração switch;

·        Expressão switch.

 

 

2 – Declaração switch

 

A instrução switch consiste em um bloco que contém uma sequência de rótulos case e um rótulo default, opcional. 

Em Java, a sintaxe da declaração switch (“switch statement”) é a seguinte:


image 


switch(valor) {

           case valor_1: comandos_1;

                                  break;

            case valor_2: comandos_2;

                                  break;

            case valor_N: comandos_N;

            break;

            default: comandos_default;

                        break; 

}

 

O valor (ou expressão) entre parênteses é chamado expressão de controle do switch. Ele deve ser um valor inteiro (do tipo byte, char, short ou int), um tipo enumerado ou um String. Se for usado um tipo diferente de variável, resulta em erro.

 

A expressão é avaliada e seu valor é comparado com os valores dos vários rótulos ”case”.

 

Se ocorrer uma correspondência, o programa executa o bloco de instruções deste case, até encontrar uma instrução “break” ou o final do switch.

 

A instrução break transfere imediatamente o controle do programa para a primeira instrução após o switch.

 

Caso um rótulo case não tenha uma instrução break a execução do programa continua sucessivamente com as instruções dos rótulos “case” subsequentes, até encontrar um break ou o fim do switch. Esse processo é chamado fall through”.

 

O rótulo default é opcional e a instrução break do rótulo default também é opcional.

 

Note que a instrução switch não exige que o bloco de instruções de um case esteja entre chaves, diferentemente de outras instruções de controle (if, if-else).

 

A instrução switch não fornece um mecanismo para testar faixas de valores, então todo valor que você precisa testar deve ser listado em um rótulo case separado.

 

Se não ocorrer nenhuma correspondência entre o valor da expressão de controle e um rótulo case, o caso default será executado.

 

Em geral, usa-se caso default para processar todos os valores da expressão de controle que não têm um rótulo case associado.

 

Se não ocorrer nenhuma correspondência e o switch não contiver um caso default, o controle de programa simplesmente continua com a primeira instrução depois do switch.

 

 Esta instrução (“switch assignment”) representa o modelo clássico dessa estrutura, oferecido por várias linguagens, algumas vezes com nome ou sintaxe ligeiramente diferente.

 

Note que o formato de cada rótulo case segue a sintaxe “case L: instrução;”.

  

Exemplo de uso 1 - simulação da operação de um menu

 

 

public class Main {
  public static void main(String[] args) {
 
 int opcaoMenu = 1;
 switch (opcaoMenu) {
     case 1: System.out.println("Abrir arquivo"); break;
     case 2: System.out.println("Salvar arquivo"); break;
     case 3: System.out.println("Imprimir"); break;
     case 4: System.out.println("Sair do programa"); break;
     }
 }
}

 

 Exemplo de uso 2, usando um tipo enumerado - contagem do número de letras dos dias da semana

 

 public class Main {
 public enum DiaDaSemana { DOMINGO, SEGUNDA, TERCA, QUARTA, QUINTA, SEXTA, SABADO; }
 
 public static void main(String[] args) {
     int numLetras = 0;
     DiaDaSemana dia = DiaDaSemana.QUARTA;
     switch (dia) {
         case TERCA:
         case SEXTA:
             numLetras = 5;
             break;
 
         case QUARTA:
         case QUINTA:
         case SABADO:
             numLetras = 6;
             break;
     
         case SEGUNDA:
         case DOMINGO:
             numLetras = 7;
             break;
         default:
             throw new IllegalStateException("Dia inválido: " + dia);
     }
     System.out.println(numLetras);
 }
}

 

 Exemplo de uso 3, usando um String - testa nome de uma linguagem e escreve o nome do seu criador

 

public class Main {
 public static void main(String[] args) {
 
     String linguagem = "Java";
     switch (linguagem) {
         case "Java": System.out.println("criador: James Gosling"); break;
         case "Python": System.out.println("criador: Guidovan Rossum"); break;
         case "C": System.out.println("criador: Dennis Ritchie"); break;
         default: System.out.println("Linguagem não tratada"); 
     }
 }
}

 

 Problemas com esta instrução

 

A instrução switch-case do tipo “switch statement” apresenta alguns problemas, que exigem a atenção do programador para que ele não incorra em erros de lógica nem de sintaxe:

 

·        A instrução break não é obrigatória, mas seu esquecimento resulta na execução de todas as instruções seguintes, para os diversos rótulos case, até que seja encontrado um break ou o fim do switch. É uma fonte de erros lógicos;

·        Ausência de tratamento para um valor da variável – Os rótulos “case” de um switch devem ser exaustivos, ou seja, deve ter um case para cada um dos valores que podem ser testados, senão resultará em erro. A solução é adicionar uma cláusula “default”;

  

4 – Expressão switch

 

Esta instrução (“switch expression”) foi criada para modernizar a declaração switch-case tradicional existente. Ele segue o mesmo fluxograma da figura mostrada no início da seção anterior.

 

As diferenças principais são as seguintes:

·        Ele pode conter rótulos "case L ->", com sintaxe semelhante à uma “arrow function” (embora não sejam “arrow functions”), que eliminam a necessidade de instruções break, evitando erros comuns;

·        O valor associado à execução do switch pode ser retornado (por exemplo, para atribuição à uma variável) pela instrução “yield”, diferenciando da instrução tradicional de retorno “return”;

 

 

O novo tipo de rótulo tem o seguinte formato:

 

case valor_1, ..., valor_N -> expressão; | instrução “throw” | bloco de instruções

 

Quando o teste coincide com algum valor à esquerda da seta, o código à direita da seta é executado, não sendo executao nenhum outro código de “cases" subsequentes. Se o código à direita da seta for uma expressão, o valor dessa expressão será o valor da expressão switch.

 

Você pode usar o novo tipo de rótulo case em instruções do tipo “switch statement”, apenas trocando os rótulos “case L:” por "case L ->".

 

A instrução yield facilita a diferenciação entre instruções switch e expressões switch, pois a instrução break só pode ser usada na instrução “switch statement” enquanto uma instrução yield só pode ser usada em uma instrução “switch expression”.

  

Exemplo de uso 4, usando rótulos “case L ->” - imprime o número de letras de um dia da semana):

  

Vamos fazer algumas melhorias no código do exemplo 2, usando a sintaxe da expressão switch. Segue a versão deste código:

  

public class Main {
 public enum DiaDaSemana { DOMINGO, SEGUNDA, TERCA, QUARTA, QUINTA, SEXTA, SABADO; }
 
 public static void main(String[] args) {
     int numLetras = 0;
     DiaDaSemana dia = DiaDaSemana.QUARTA;
     switch (dia) {
         case TERCA, SEXTA -> numLetras = 5;
         case QUARTA, QUINTA, SABADO -> numLetras = 6;
         case SEGUNDA, DOMINGO -> numLetras = 7;
         default -> throw new IllegalStateException("Dia inválido: " + dia);
     }
     System.out.println(numLetras);
 }
}

  

Outra melhora pode ser feita usando o retorno da expressão switch, com a instrução “yield”. Para rótulos "case L ->", para especificar diversas instruções ou códigos que não sejam expressões ou instruções “throw”, eles devem ser colocados em um bloco.

   

Exemplo de uso 5, usando “yield” - imprime o número de letras de um dia da semana):

 

 

public class Main {
 public enum DiaDaSemana { DOMINGO, SEGUNDA, TERCA, QUARTA, QUINTA, SEXTA, SABADO; }
 
  public static void main(String[] args) {
     DiaDaSemana dia = DiaDaSemana.QUARTA;
 
     int numLetras = switch (dia) {
         case TERCA, SEXTA -> {
             System.out.println(5);
             yield(5);
         }
         case QUARTA, QUINTA, SABADO -> {
             System.out.println(6);
             yield(6);
         }
         case SEGUNDA, DOMINGO -> {
             System.out.println(7);
             yield(7);
         }
         default -> throw new IllegalStateException("Dia inválido: " + dia);
     };
 }
}

 

 Recomendações sobre o uso do switch-case:

 

·        Use rótulos "case L ->". É fácil esquecer de inserir instruções break ou yield ao usar rótulos “case L:”; se fizer isso, você poderá introduzir falhas não intencionais em seu código.

·        Os rótulos “case” deste tipo de switch também devem ser exaustivos, ou seja, deve ter um case para cada um dos valores que podem ser testados, senão resultará em erro. A solução é adicionar uma cláusula “default”;

·        Uma expressão switch deste tipo deve ser avaliada como um único valor (ou gerar uma exceção) e um bloco deve ter uma instrução de retorno “yield”, caso contrário, o código nem vai compilar, como no trecho de código a seguir:

 

 

int i = switch (day) {

   case DOMINGO -> {

       System.out.println("Domingo");

       // ERROR! O bloco não contém uma instrução “yield”

   }

   default -> 1;

};

 

  

5 – Considerações finais

Este artigo apresentou a instrução switch-case, tratando especificamente do seu uso na linguagem Java.

 

Ela é uma das instruções mais comuns de seleção, presentes em todas as linguagens de programação que eu conheço. 

 

Ele é uma versão melhorada da instrução if-else, cujo uso em uma quantidade grande de testes pode tornar difícil a leitura, entendimento e manutenção pelos programadores. No entanto, em alguns casos, como teste de faixas de valores, ela ainda é muito usada e até recomendada, pois a instrução switch-case só testa valores inteiros.

 

A linguagem java oferece dois tipos de instruções switch-case: a declaração switch (“switch statement”) e a expressão switch (“switch expression”), esta uma forma diferente do swirtch tradicional, pois permite retorno de um valor para ser atribuído a uma variável, uma nova sintaxe para tratamento dos diversos rótulos case, dispensando o uso do break, fonte de erros lógicos, por esquecimento no seu uso, além de uma nova forma de retornar valores dentro da própria instrução switch, por meio da instrução “yield”, que diferencia o retorno comum de funções usando “return”.

 

 6 – Referências

 

Documentação Oficial do Java:

[1] https://docs.oracle.com/en/java/javase/21/language/switch-expressions.html#GUID-BA4F63E3-4823-43C6-A5F3-BAA4A2EF3ADC

 

[2] https://docs.oracle.com/en/industries/life-sciences/clinical-one/rules-dg/general-switch-statement.html#GUID-C2AA8CC4-76A3-411E-B23B-AA32EF3A4A03

 

[3] https://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html

 

Compartilhe
Comentários (4)
Fernando Araujo
Fernando Araujo - 11/02/2024 11:13

Verdade, André! Mas é o que a linguagem nos oferece.

Iniciantes podem começar com ela, substituindo as escadinhas de if-else e, só depois, aprendem a usar técnicas melhores.

Fernando Araujo
Fernando Araujo - 11/02/2024 11:11

Obrigado, Luis!

A modernidade faz com que os comandos tradicionais sofram atualizações, tanto para corrigir falhas e limitações quanto para se adaptar às novas aplicações.

É o caso deste comando Switch Expression em relação ao Switch Statement.

André Bezerra
André Bezerra - 09/02/2024 23:43

Nunca uso essa função ^^ heuheuheuehue muito limitada.

Luis Zancanela
Luis Zancanela - 09/02/2024 18:25

Muito legal o artigo. Explica bem o switch case e o uso do yield. Switch case e enums andam bem juntos.