Expresiones switch en Java
Expresiones switch modernas en Java con sintaxis de flecha, yield y coincidencia de patrones exhaustiva.
Java 14 promovió las expresiones switch como característica estándar del lenguaje. Se construyen sobre la sentencia switch tradicional con tres grandes mejoras: producen un valor, usan una sintaxis de flecha más limpia y hacen imposible el fall-through. Si usas Java 14 o una versión más reciente, dales preferencia.
Este capítulo cubre la sintaxis de flecha, la palabra clave yield para cuerpos de bloque, la verificación de exhaustividad y la coincidencia de patrones basada en tipos que se convirtió en estándar en Java 21. Al final sabrás cuándo conviene usar una expresión switch en lugar de una cadena if/else.
Sentencia vs. expresión
La switch tradicional es una sentencia: hace algo (ejecuta efectos secundarios) pero no produce un valor. Una expresión switch se evalúa a un valor que puedes asignar, retornar o pasar a un método. Esa única diferencia impulsa todo lo demás en esta página: porque el resultado se usa, el compilador puede exigir que cada rama produzca un valor y que ninguna entrada quede sin manejar.
Sintaxis de forma con flecha
String day = "TUE";
String label = switch (day) {
case "MON", "TUE", "WED", "THU", "FRI" -> "weekday";
case "SAT", "SUN" -> "weekend";
default -> "unknown";
};Tres cosas a notar:
- El
switchcompleto es una expresión: se evalúa a un valor que puedes asignar (observa el;al final). - Cada caso usa
->en lugar de:. El lado derecho es una sola sentencia o expresión. - Se permiten múltiples etiquetas en un mismo caso, separadas por comas. Sin
break, sin fall-through.
Cuerpos de bloque con yield
Si un caso necesita varias sentencias, usa un bloque — y dentro del bloque, devuelve el valor con 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 es como return, pero para la expresión switch: establece el valor de este switch y sale del caso. (No lo confundas con return, que saldría del método que lo contiene.)
Solo necesitas yield dentro de un bloque ({ ... }). Un caso de expresión única como case 8 -> "B"; ya devuelve su valor directamente, por lo que agregar yield allí sería un error de compilación.
yield es una palabra clave contextual: solo actúa como palabra clave dentro de un bloque switch. El código que usaba yield como nombre de variable o de método antes de Java 14 sigue compilando, por lo que adoptar expresiones switch nunca rompe los identificadores existentes.
Las sentencias siguen funcionando
También puedes usar la sintaxis de flecha para efectos secundarios; en ese caso es una sentencia, no una expresión:
switch (day) {
case "MON", "TUE", "WED", "THU", "FRI" -> System.out.println("weekday");
case "SAT", "SUN" -> System.out.println("weekend");
default -> System.out.println("unknown");
}La ventaja sobre la forma antigua: sin break, sin errores de fall-through, además de los casos con múltiples etiquetas descritos arriba.
Exhaustividad
Cuando una expresión switch asigna a una variable, el compilador requiere que cada posible entrada produzca un valor. Para un enum, eso significa cubrir todas las constantes o proporcionar un 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 coveredSi luego agregas una nueva constante al enum y olvidas actualizar el switch, el compilador te lo dirá. Esa es una garantía de corrección que no obtienes con if/else.
Coincidencia de patrones (Java 21+)
Java 21 convirtió en estándar la coincidencia de patrones para switch. Puedes hacer switch sobre el tipo de un valor y vincularlo a una variable tipada dentro del caso:
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";
};La cláusula when es un guard: restringe un caso más aún con una condición boolean. Esto reemplaza muchas cadenas de instanceof, y se combina naturalmente con las características más amplias de coincidencia de patrones.
Dos reglas a tener en cuenta:
- Un
switchtradicional rechaza un selectornullcon unaNullPointerException. Un switch de patrones puede incluir uncase nullexplícito: sin él, unnullsigue lanzando la excepción. Ya no es posible pasar por alto quenullllega al switch silenciosamente. - Los casos se evalúan de arriba a abajo, así que ordénalos de más específico a más general. El
case Integer i when i < 0con guard debe ir antes que el simplecase Integer i, o el caso sin guard absorbería primero todos los enteros.
Un ejemplo completo
¿Qué sigue?
Hemos cubierto los condicionales. A continuación vienen los bucles: el bucle while es el más sencillo de todos.