Translate

lunes, 22 de septiembre de 2025

Records en Java: Clases Inmutables de Forma Sencilla



A partir de Java 14 (como preview) y de forma estable en Java 16, se introdujeron los records.

Un record es una forma concisa de declarar clases inmutables que sirven principalmente para transportar datos (clases DTO, value objects, etc.).

La sintaxis básica es:

public record Persona(String nombre, int edad) {}


Esto genera automáticamente:

  • Los campos privados y finales nombre y edad.
  • Un constructor que inicializa esos campos.
  • Los métodos getters nombre() y edad().
  • Una implementación de toString().
  • Métodos equals() y hashCode() basados en los campos.


Veamos un ejemplo de uso: 


public class Main {

    public static void main(String[] args) {

        Persona p = new Persona("Ana", 30);


        System.out.println(p.nombre()); // "Ana"

        System.out.println(p.edad());   // 30

        System.out.println(p);          // Persona[nombre=Ana, edad=30]

    }

}


Notá que no se usan getNombre() ni getEdad(), sino directamente nombre() y edad().

Los campos de un record son inmutables (implícitamente final).

No existe p.setEdad(31) → en su lugar, deberías crear un nuevo objeto Persona.


Aunque el record genera mucho código automáticamente, también podés definir métodos adicionales:


public record Persona(String nombre, int edad) {

    public boolean esMayorDeEdad() {

        return edad >= 18;

    }

}


Persona juan = new Persona("Juan", 17);

System.out.println(juan.esMayorDeEdad()); // false


Podés agregar lógica en el constructor, pero siempre respetando la inicialización de todos los campos:


public record Persona(String nombre, int edad) {

    public Persona {

        if (edad < 0) {

            throw new IllegalArgumentException("La edad no puede ser negativa");

        }

    }

}


Este es el constructor compacto: no es necesario repetir la asignación de campos, Java lo hace automáticamente.


Los records funcionan muy bien como DTOs, por ejemplo en listas o streams:


List<Persona> personas = List.of(

    new Persona("Ana", 30),

    new Persona("Luis", 25)

);


personas.stream()

    .filter(p -> p.edad() > 26)

    .forEach(System.out::println);


En Resumen: 

  • Los records simplifican la creación de clases para transportar datos.
  • Generan automáticamente: constructor, getters, equals, hashCode y toString.
  • Son inmutables por diseño.
  • Se pueden añadir métodos y validaciones de construcción.


Son ideales para DTOs, value objects y cualquier situación en la que antes usabas una clase con solo atributos y getters.