CodeGym /Cursos /JAVA 25 SELF /Pattern matching en switch (Java 17/21+)

Pattern matching en switch (Java 17/21+)

JAVA 25 SELF
Nivel 65, Lección 2
Disponible

1. Switch clásico: limitaciones del pasado

Recordemos cómo era el switch en Java antes de la aparición del pattern matching. Era, siendo sinceros, bastante conservador. Solo funcionaba con tipos primitivos (int, char, y, algo más tarde, enum, String), y si querías procesar distintos tipos de objetos, había que escribir largas cadenas de if-else.

Object obj = ...;
if (obj instanceof String) {
    String s = (String) obj;
    System.out.println("Cadena: " + s);
} else if (obj instanceof Integer) {
    Integer i = (Integer) obj;
    System.out.println("Número: " + i);
} else if (obj == null) {
    System.out.println("¡null!");
} else {
    System.out.println("Algo más");
}

¿Cómodo? No mucho. El código es voluminoso, es fácil equivocarse y, si aparece un tipo nuevo, tendrás que volver a reescribir la cadena de if-else.

2. Pattern matching en switch: una revolución en Java 17/21+

Java 17 (preview) y, definitivamente, en Java 21+, presentaron una nueva versión de switch que admite coincidencia de patrones (pattern matching). Ahora switch puede trabajar no solo con primitivos, sino también con cualquier objeto, tipos, incluso con null, y admite condiciones adicionales (guard-conditions).

Nueva sintaxis: concisión y potencia

Ejemplo sencillo de pattern matching en switch:

Object obj = ...;
switch (obj) {
    case String s -> System.out.println("Cadena: " + s);
    case Integer i -> System.out.println("Número: " + i);
    case null -> System.out.println("¡null!");
    default -> System.out.println("Algo más");
}

¿Qué ocurre aquí?

  • Si obj es una cadena, la variable s se convierte automáticamente al tipo String.
  • Si obj es un entero, la variable i pasa a ser Integer.
  • Si obj es null, se ejecuta una rama específica.
  • Todo lo demás — default.

¿Por qué es útil?

  • No hay casting manual de tipos: Java se ocupa de la seguridad de tipos.
  • Menos código: Nada de paréntesis extra, casts ni duplicaciones.
  • Más seguro: El compilador comprueba que no olvides manejar las variantes posibles (especialmente con sealed-clases, de las que hablaremos más adelante).
  • Fácil de añadir nuevos tipos: Simplemente añade otra rama case.

3. Pattern matching en switch: ejemplos básicos

Ejemplo 1: Manejo de distintos tipos

Object obj = 42;

switch (obj) {
    case String s -> System.out.println("Cadena: " + s);
    case Integer i -> System.out.println("Número: " + i);
    case null -> System.out.println("Es null");
    default -> System.out.println("Tipo desconocido");
}

Salida:

Número: 42

Ejemplo 2: Uso de condiciones de guarda (when)

A veces no basta con conocer el tipo — se quiere añadir una condición adicional.

Object obj = "Hello, world!";

switch (obj) {
    case String s when s.length() > 10 -> System.out.println("Cadena larga: " + s);
    case String s -> System.out.println("Cadena corta: " + s);
    case Integer i when i > 0 -> System.out.println("Número positivo: " + i);
    case Integer i -> System.out.println("Número no positivo: " + i);
    default -> System.out.println("Algo más");
}

Salida:

Cadena larga: Hello, world!

Ten en cuenta:

  • when es una condición de guarda, una comprobación adicional para case.
  • Si la condición no se cumple, se evalúan los siguientes case.

Ejemplo 3: Manejo de null

Object obj = null;

switch (obj) {
    case null -> System.out.println("¡Es null!");
    default -> System.out.println("No es null");
}

Salida:

¡Es null!

4. Pattern matching en switch con clases y herencia

El pattern matching en switch funciona especialmente bien con jerarquías de clases.

sealed interface Shape permits Circle, Rectangle, Square {}

final class Circle implements Shape {
    final double radius;
    Circle(double radius) { this.radius = radius; }
}

final class Rectangle implements Shape {
    final double width, height;
    Rectangle(double width, double height) { this.width = width; this.height = height; }
}

final class Square implements Shape {
    final double side;
    Square(double side) { this.side = side; }
}
Shape shape = new Rectangle(2, 3);

String description = switch (shape) {
    case Circle c -> "Círculo de radio " + c.radius;
    case Rectangle r -> "Rectángulo " + r.width + "x" + r.height;
    case Square s -> "Cuadrado con lado " + s.side;
};
System.out.println(description);

Salida:

Rectángulo 2.0x3.0

Ventaja: Si utilizas clases sealed y has manejado todas sus variantes, la rama default no es necesaria: ¡el compilador entiende que no puede haber más casos!

5. Uso de switch con clases record y patrones anidados

El pattern matching en switch admite trabajar con clases record y patrones anidados (a partir de Java 21+).

record Point(int x, int y) {}
record Line(Point start, Point end) {}

Object obj = new Line(new Point(1, 2), new Point(3, 4));

String result = switch (obj) {
    case Line(Point(int x1, int y1), Point(int x2, int y2)) ->
        "Línea de (" + x1 + "," + y1 + ") a (" + x2 + "," + y2 + ")";
    case Point(int x, int y) -> "Punto (" + x + "," + y + ")";
    default -> "Objeto desconocido";
};
System.out.println(result);

Salida:

Línea de (1,2) a (3,4)

6. Particularidades y limitaciones del pattern matching en switch

Las variables solo están disponibles dentro del case

La variable declarada en el patrón (por ejemplo, String s) existe únicamente dentro del bloque case correspondiente. Fuera de él no está disponible.

switch (obj) {
    case String s -> System.out.println(s); // aquí s es visible
    // System.out.println(s); // ¡aquí hay un error de compilación!
}

Manejo de null

  • En el antiguo switch sobre objetos, intentar pasar null provocaba un NullPointerException.
  • En el nuevo pattern matching de switch se puede manejar null explícitamente mediante case null.

Condiciones de guarda (when)

Las condiciones adicionales (when) están disponibles solo en el switch de estilo expresión (sintaxis con flecha ->).

case String s when s.isEmpty() -> System.out.println("Cadena vacía");

Requisitos de JDK e IDE

  • El pattern matching en switch es una característica de Java 17 (preview) y Java 21+ (estable).
  • Para usarlo necesitas JDK 21 y un IDE que soporte las nuevas funcionalidades (por ejemplo, IntelliJ IDEA 2023+).

7. Aplicación del pattern matching en switch en una aplicación real

Veamos una aplicación de ejemplo — un sencillo gestor de tareas. Supongamos que tienes un tipo abstracto de tarea y diferentes variantes:

sealed interface Task permits SimpleTask, DeadlineTask, MeetingTask {}

final class SimpleTask implements Task {
    final String description;
    SimpleTask(String description) { this.description = description; }
}

final class DeadlineTask implements Task {
    final String description;
    final java.time.LocalDate deadline;
    DeadlineTask(String description, java.time.LocalDate deadline) {
        this.description = description;
        this.deadline = deadline;
    }
}

final class MeetingTask implements Task {
    final String topic;
    final java.time.LocalTime time;
    MeetingTask(String topic, java.time.LocalTime time) {
        this.topic = topic;
        this.time = time;
    }
}

Toda la lógica en un único switch compacto:

Task task = new DeadlineTask("Entregar el proyecto", java.time.LocalDate.of(2024, 7, 1));

String info = switch (task) {
    case SimpleTask st -> "Tarea simple: " + st.description;
    case DeadlineTask dt -> "Tarea con fecha límite: " + dt.description + ", hasta " + dt.deadline;
    case MeetingTask mt -> "Reunión: " + mt.topic + " a las " + mt.time;
};
System.out.println(info);

Salida:

Tarea con fecha límite: Entregar el proyecto, hasta 2024-07-01

8. Errores típicos al usar pattern matching en switch

Error n.º 1: olvidaste manejar null. Si no añades case null y obj puede ser null, obtendrás MatchException (o NullPointerException en los switch antiguos). Maneja siempre null explícitamente cuando sea posible.

Error n.º 2: no tuviste en cuenta todos los subtipos del sealed-clase. Si utilizas una clase sealed y no manejas todas las variantes en el switch, el compilador dará error o exigirá una rama default. No olvides añadir nuevos case al ampliar la jerarquía.

Error n.º 3: la variable del patrón no está disponible fuera del bloque case. La variable declarada en el patrón existe solo dentro del bloque con flecha. Intentar usarla fuera de ese bloque provocará un error de compilación.

Error n.º 4: usar funciones nuevas con una JDK o un IDE antiguos. El pattern matching en switch requiere Java 21+ y soporte correspondiente en tu IDE. Si usas una versión antigua, obtendrás un error de compilación o sugerencias incorrectas.

Error n.º 5: confusiones con las condiciones de guarda. ¿Intentas usar when en un switch de bloque antiguo? No va a funcionar. Las guardas solo están disponibles con la sintaxis de flecha ->.

Error n.º 6: olvidar la rama default al trabajar con jerarquías abiertas. Si tu switch no trabaja únicamente con clases sealed, añade siempre default — de lo contrario, no se cubrirán todas las variantes.

1
Tarea
JAVA 25 SELF, nivel 65, lección 2
Bloqueada
Clasificador de números para el sistema de análisis 🔢
Clasificador de números para el sistema de análisis 🔢
1
Tarea
JAVA 25 SELF, nivel 65, lección 2
Bloqueada
Sistema inteligente de identificación de mascotas para la clínica veterinaria 🐕🐈🦜
Sistema inteligente de identificación de mascotas para la clínica veterinaria 🐕🐈🦜
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION