Java Moderno agrupa las features de lenguaje introducidas entre Java 14 y Java 21 que cambiaron la forma de escribir código Java idiomático. Son features de expresividad: eliminan boilerplate, hacen imposibles ciertos bugs y permiten modelar dominios con más precisión.
Las cinco features principales son:
- Records (Java 16 estable): clases de datos inmutables con componentes declarados en la cabecera. El compilador genera constructor canónico,
equals,hashCodeytoStringautomáticamente. - Sealed Classes (Java 17 estable): jerarquías cerradas donde el compilador conoce todas las subclases. Permiten exhaustiveness checking en switch.
- Pattern Matching (Java 16+ para
instanceof, Java 21 para switch): combina test de tipo + binding variable en una sola expresión. Elimina casts explícitos y code smells del tipo "check and cast". - Switch Expressions (Java 14 estable): switch que produce un valor, con sintaxis de flecha
->que elimina fall-through accidental. Soportayieldpara casos con lógica. - Text Blocks (Java 15 estable): strings multilínea con indentación inteligente. Ideales para JSON, SQL, HTML y XML embebidos en código.
Estas features no son independientes: Records + Sealed Classes + Pattern Matching en Switch forman un sistema cohesivo para modelar datos algebraicos en Java, similar a los ADTs de lenguajes funcionales.
Records
// Declaración: componentes en la cabecera record Punto(double x, double y) { // Compact constructor: validación sin repetir parámetros Punto { if (x < 0 || y < 0) throw new IllegalArgumentException("Coordenadas negativas"); } // Métodos custom: igual que una clase normal double distanciaAlOrigen() { return Math.sqrt(x * x + y * y); } static Punto ORIGEN = new Punto(0, 0); }
El compilador genera: Punto(double x, double y), x(), y(), equals, hashCode, toString. Los records son implícitamente final y sus componentes son private final.
Sealed Classes
// La jerarquía está cerrada: solo estas implementaciones sealed interface Forma permits Circulo, Rectangulo, Triangulo {} record Circulo(double radio) implements Forma {} record Rectangulo(double ancho, double alto) implements Forma {} final class Triangulo implements Forma { /* ... */ }
Las subclases de una sealed class deben ser final, sealed o non-sealed. El compilador puede verificar exhaustiveness.
Pattern Matching
// instanceof con binding variable (Java 16) if (obj instanceof String s && s.length() > 5) { System.out.println(s.toUpperCase()); // s ya es String, sin cast } // Guarded pattern en switch (Java 21) String resultado = switch (forma) { case Circulo c when c.radio() > 10 -> "circulo grande"; case Circulo c -> "circulo pequenyo"; case Rectangulo r -> "rectangulo " + r.ancho() + "x" + r.alto(); case Triangulo t -> "triangulo"; };
Switch Expressions
// Arrow label: sin fall-through, sin break, produce un valor int numLetras = switch (dia) { case LUNES, VIERNES, DOMINGO -> 6; case MARTES -> 7; case JUEVES, SABADO -> 8; case MIERCOLES -> 9; }; // yield: necesario cuando el case tiene lógica String categoria = switch (valor) { case 1, 2 -> "bajo"; default -> { String msg = "valor-" + valor; yield msg.toUpperCase(); } };
Text Blocks
String json = """ { "nombre": "Java", "version": 21, "features": ["records", "sealed", "patterns"] } """; // La indentación común se elimina automáticamente // La primera línea de contenido real empieza justo después de """
- Menos boilerplate: Records eliminan los getters, constructores y
equals/hashCodemanuales que antes requerían Lombok o generación de IDE. - Type safety mejorado: Sealed classes hacen que el compilador conozca todas las variantes posibles de una jerarquía, habilitando exhaustiveness checking real.
- Código más expresivo: Pattern matching elimina el patrón tedioso de
instanceof+ cast + variable. El código dice lo que hace. - Strings legibles: Text blocks permiten incrustar JSON, SQL o HTML sin escapes ni concatenaciones. El código fuente y la string resultante tienen la misma forma.
- Switch seguro: Switch expressions eliminan el fall-through accidental (bug histórico de Java) y permiten usar switch donde antes solo cabía una expresión ternaria o una variable mutable.
- Modelado algebraico: Records + Sealed + Pattern Matching juntos permiten tipos de datos algebraicos (ADTs) similares a los de Haskell o Rust, con verificación del compilador.
Ver los archivos Exp*.java para ejemplos ejecutables de cada feature.