Expressões Switch em Java
Expressões switch modernas em Java com sintaxe de seta, yield e correspondência de padrões exaustiva.
O Java 14 elevou as expressões switch a um recurso padrão da linguagem. Elas se baseiam na instrução switch tradicional com três grandes melhorias: produzem um valor, usam uma sintaxe de seta mais limpa e tornam o fall-through impossível. Se você está no Java 14 ou mais recente, prefira-as.
Este capítulo cobre a sintaxe de seta, a palavra-chave yield para corpos de bloco, verificação de exaustividade e a correspondência de padrões baseada em tipos que se tornou padrão no Java 21. Ao final, você saberá quando usar uma expressão switch em vez de uma cadeia if/else.
Instrução vs. expressão
O switch tradicional é uma instrução: ele faz algo (executa efeitos colaterais), mas não produz valor. Uma expressão switch avalia para um valor que você pode atribuir, retornar ou passar para um método. Essa única diferença impulsiona tudo o mais nesta página — porque o resultado é usado, o compilador pode exigir que cada ramo produza um valor e que nenhuma entrada passe despercebida.
Sintaxe de seta
String day = "TUE";
String label = switch (day) {
case "MON", "TUE", "WED", "THU", "FRI" -> "weekday";
case "SAT", "SUN" -> "weekend";
default -> "unknown";
};Três coisas a observar:
- O
switchinteiro é uma expressão — avalia para um valor que você pode atribuir (observe o;final). - Cada case usa
->em vez de:. O lado direito é uma instrução ou expressão. - Múltiplos rótulos são permitidos em um case, separados por vírgula. Sem
break, sem fall-through.
Corpos de bloco com yield
Se um case precisar de múltiplas instruções, use um bloco — e dentro do bloco, retorne o valor com yield:
int score = 78;
String grade = switch (score / 10) {
case 10, 9 -> "A";
case 8 -> "B";
case 7 -> {
System.out.println("close to B");
yield "C";
}
case 6 -> "D";
default -> "F";
};yield é como return, mas para a expressão switch — ele define o valor desta expressão switch e sai do case. (Não o confunda com return, que sairia do método envolvente.)
Você só precisa de yield dentro de um bloco ({ ... }). Um case de expressão única como case 8 -> "B"; já retorna seu valor diretamente, então adicionar yield ali seria um erro de compilação.
yield é uma palavra-chave contextual: ela só atua como palavra-chave dentro de um bloco switch. Código que usava yield como nome de variável ou método antes do Java 14 ainda compila, portanto adotar expressões switch nunca quebra identificadores existentes.
Instruções ainda funcionam
Você também pode usar a sintaxe de seta para efeitos colaterais; nesse caso, é uma instrução, não uma expressão:
switch (day) {
case "MON", "TUE", "WED", "THU", "FRI" -> System.out.println("weekday");
case "SAT", "SUN" -> System.out.println("weekend");
default -> System.out.println("unknown");
}A vantagem sobre a forma antiga: sem break, sem bugs de fall-through, além dos cases com múltiplos rótulos acima.
Exaustividade
Quando uma expressão switch atribui a uma variável, o compilador exige que toda entrada possível produza um valor. Para um enum, isso significa cobrir todas as constantes ou fornecer um default:
enum Status { PENDING, ACTIVE, DONE }
Status s = Status.ACTIVE;
String label = switch (s) {
case PENDING -> "waiting";
case ACTIVE -> "running";
case DONE -> "complete";
}; // no default needed — all enum values are coveredSe você adicionar uma nova constante ao enum posteriormente e esquecer de atualizar o switch, o compilador irá informá-lo. Essa é uma forte garantia de correção que você não obtém com if/else.
Correspondência de padrões (Java 21+)
O Java 21 tornou a correspondência de padrões para switch um recurso padrão. Você pode alternar com base no tipo de um valor e vinculá-lo a uma variável tipada dentro do case:
Object o = 42;
String description = switch (o) {
case Integer i when i < 0 -> "negative int: " + i;
case Integer i -> "non-negative int: " + i;
case String s -> "string of length " + s.length();
case null -> "null value";
default -> "something else";
};A cláusula when é uma guarda — ela refina ainda mais um case com uma condição booleana. Isso substitui muitas cadeias de instanceof e se combina naturalmente com os recursos mais amplos de correspondência de padrões.
Duas regras a ter em mente:
- Um
switchtradicional rejeita um seletornullcom umaNullPointerException. Um switch de padrões pode incluir umcase nullexplícito — sem ele, umnullainda lança a exceção. Deixarnullchegar ao switch silenciosamente não é mais algo que passe despercebido. - Os cases são testados de cima para baixo, portanto ordene do mais específico ao mais geral. O
case Integer i when i < 0com guarda deve vir antes do simplescase Integer i, ou o case sem guarda englobaria todos os inteiros primeiro.
Um exemplo prático
O que vem a seguir
Cobrimos os condicionais. A seguir vêm os laços: o laço while é o mais simples deles.