Records (Java 16+)
Parte de la sección Programación Orientada a Objetos del Journey de Java de Coddy. Lección 51 de 87.
Al crear clases sencillas que contienen datos, a menudo escribes código repetitivo: campos privados, un constructor, getters, toString(), equals() y hashCode(). Java 16 introdujo los registros para eliminar esta tediosa tarea.
Un record es una clase especial diseñada para contener datos inmutables. Se declara con la palabra clave record seguida de la lista de componentes:
record Person(String name, int age) { }
// Esa única línea proporciona automáticamente:
// - campos private final: name y age
// - un constructor: Person(String name, int age)
// - métodos de acceso: name() y age()
// - toString(), equals() y hashCode()Usar un record es sencillo:
Person p = new Person("Alice", 30);
System.out.println(p.name()); // Alice
System.out.println(p.age()); // 30
System.out.println(p); // Person[name=Alice, age=30]Observa que los métodos de acceso no usan el prefijo get: simplemente reciben el nombre de los campos. Los registros son implícitamente final, por lo que no se pueden extender. Todos los campos también son final, lo que hace que los registros sean inmutables por naturaleza.
Puedes añadir métodos personalizados y sobrescribir los generados automáticamente si es necesario. También puedes añadir validación en un constructor compacto:
record Person(String name, int age) {
public Person {
if (age < 0) throw new IllegalArgumentException("Age cannot be negative");
}
}Los registros son perfectos para DTO, respuestas de API o cualquier situación en la que necesites un contenedor de datos simple e inmutable sin escribir código repetitivo.
Desafío
FácilConstruyamos un sistema de reserva de entradas de cine que muestre la elegancia de los registros de Java. Verás cómo los registros eliminan el código repetitivo y, al mismo tiempo, te permiten añadir métodos personalizados y validación.
Organizarás tu código en tres archivos:
Movie.java: Crea un registro que represente una película con tres componentes:title(String),genre(String) ydurationMinutes(int). Añade un método personalizado llamadogetFormattedDuration()que devuelva la duración en un formato sencillo:[hours]h [minutes]m(por ejemplo, 142 minutos se convierten en2h 22m). Usa la división entera y el módulo para calcular las horas y los minutos restantes.Ticket.java: Crea un registro que represente una entrada de cine con tres componentes:movie(Movie),seatNumber(String) yprice(double). Añade un constructor compacto que valide el precio; si el precio es menor o igual que cero, lanza unaIllegalArgumentExceptioncon el mensajePrice must be positive. Añade también un método personalizado llamadoprintTicket()que devuelva una cadena multilínea:========== TICKET ========== Movie: [movie title] Genre: [movie genre] Duration: [formatted duration from movie] Seat: [seatNumber] Price: $[price] ============================Main.java: ¡Integra tu sistema de reservas! Recibirás cinco entradas: título de la película (String), género (String), duración en minutos (int), número de asiento (String) y precio de la entrada (double).Crea un registro Movie con las tres primeras entradas y, después, crea un registro Ticket con la película, el número de asiento y el precio. Imprime el resultado de llamar a
printTicket()en tu entrada.
Recibirás cinco entradas en este orden: título de la película, género, duración (minutos), número de asiento y precio.
Observa cuánto más limpios son los registros en comparación con las clases tradicionales: no es necesario escribir constructores, getters, toString(), equals() ni hashCode(). El constructor compacto te permite añadir validación sin repetir las asignaciones de campos, y aun así puedes añadir métodos personalizados cuando sea necesario.
Pruébalo tú mismo
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Leer entradas
String title = scanner.nextLine();
String genre = scanner.nextLine();
int durationMinutes = Integer.parseInt(scanner.nextLine());
String seatNumber = scanner.nextLine();
double price = Double.parseDouble(scanner.nextLine());
// TODO: Crea un record Movie con title, genre y durationMinutes
// TODO: Crea un record Ticket con movie, seatNumber y price
// TODO: Imprime el ticket usando el método printTicket()
}
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de OOP
Archivos externosIntroducción a la OOPClases vs. ObjetosLa palabra clave thisMétodosCampos (Atributos)Método constructorSobrecarga de constructoresResumen - Calculadora simple4Herencia
Herencia básica (extends)La palabra clave superSobrescritura de métodos (@Override)Encadenamiento de constructoresLa clase ObjectHerencia simple y multinivelPor qué no hay herencia múltiple de clasesResumen - Jerarquía de empleados7Métodos especiales y la clase Object
Método toString()equals() y hashCode()Método clone()compareTo() y ComparableInterfaz ComparatorResumen - Ordenamiento personalizado2Modificadores de acceso y encapsulamiento
Visión general de los niveles de accesoMétodos Getter y SetterOcultamiento de informaciónLa palabra clave finalResumen - Gestor de cuentas bancarias5Polimorfismo
Fundamentos de sobrecarga de métodosSobrescritura de métodos (tiempo de ejecución)Upcasting y DowncastingEl operador instanceofClases y métodos abstractosResumen - Calculadora de figuras8Conceptos avanzados de POO
Composición vs. HerenciaAgregación vs. ComposiciónClases internas, anidadas y anónimasEnums y métodos de EnumRecords (Java 16+)Clases selladas (Java 17+)11Patrones de diseño - Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón BuilderPatrón ObserverPatrón Strategy3Propiedades de clase y miembros estáticos
Variables de instancia vs. estáticasMétodos estáticosBloques estáticosConstantes (static final)Repaso - Contador y utilidad6Interfaces y Clases Abstractas
Introducción a las InterfacesImplementación de InterfacesImplementación de Múltiples InterfacesMétodos Default y Static en InterfacesClases Abstractas vs InterfacesInterfaces FuncionalesResumen - Sistema de Pagos9Genéricos
Introducción a los genéricosClases genéricasMétodos genéricosParámetros de tipo delimitadosComodines (?, extends, super)Resumen - Contenedor genérico12Patrones de diseño Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositePatrón IteratorPractica por tu cuenta: Compilador de Java online