Records em Java
A partir do Java 16, a linguagem passou a contar com um novo recurso: os records (em português, “registros”). Um record é uma classe imutável usada para armazenar dados de forma simples e expressiva, eliminando boa parte do código repetitivo necessário em classes comuns.
Records são especialmente úteis para criar contêineres de dados que não mudam após a criação do objeto, mantendo legibilidade e reduzindo erros.
Estrutura básica de um record
Um record é declarado com a palavra-chave record
, seguida do nome e, entre parênteses, os campos:
record NomeDoRecord (campo1, campo2, ... campoN) {
// corpo do record (opcional)
}
Classe tradicional vs record
Antes dos records, criar uma classe imutável exigia código repetitivo: campos final
, construtor, métodos de acesso, além de sobrescrever equals()
, hashCode()
e toString()
.
import java.util.Objects;
public class Program {
public static void main(String[] args) {
Person tom = new Person("Tom", 36);
System.out.println(tom.toString());
}
}
class Person {
private final String name;
private final int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
String name() { return name; }
int age() { return age; }
public boolean equals(Object o) {
if (!(o instanceof Person)) return false;
Person other = (Person) o;
return name.equals(other.name) && age == other.age;
}
public int hashCode() {
return Objects.hash(name, age);
}
public String toString() {
return String.format("Person[name=%s, age=%d]", name, age);
}
}
Com records, o mesmo código é reduzido a poucas linhas:
public class Program {
public static void main(String[] args) {
Person tom = new Person("Tom", 36);
System.out.println(tom.toString());
}
}
record Person(String name, int age) { }
Por padrão, um record:
- Declara seus campos como
private final
. Gera automaticamente:
- Construtor canônico com todos os campos.
- Métodos de acesso (
name()
,age()
). - Implementações de
equals()
,hashCode()
etoString()
.
Uso básico
public class Program {
public static void main(String[] args) {
Person tom = new Person("Tom", 36);
System.out.println(tom.name()); // Tom
System.out.println(tom.age()); // 36
System.out.println(tom.hashCode());
Person bob = new Person("Bob", 21);
Person tomas = new Person("Tom", 36);
System.out.println(tom.equals(bob)); // false
System.out.println(tom.equals(tomas)); // true
}
}
record Person(String name, int age) { }
Construtores em records
O construtor canônico é criado automaticamente, recebendo parâmetros com os mesmos nomes dos campos:
record Person(String name, int age) { }
É equivalente a:
Person(String name, int age) {
this.name = name;
this.age = age;
}
Customizando o construtor
Podemos validar ou alterar dados dentro do construtor canônico:
record Person(String name, int age) {
Person {
if (age < 1 || age > 110) {
age = 18;
}
}
}
Também é possível sobrescrevê-lo totalmente:
record Person(String name, int age) {
Person(String name, int age) {
if (age < 0 || age > 120) age = 18;
this.name = name;
this.age = age;
}
}
E criar outros construtores, desde que chamem o canônico:
record Person(String name, int age) {
Person(String firstName, String lastName, int age) {
this(firstName + " " + lastName, age);
}
}
Sobrescrevendo métodos
Os métodos gerados automaticamente podem ser personalizados:
record Person(String name, int age) {
public String name() {
return "Mister " + name;
}
public String toString() {
return String.format("Person %s, Age: %d", name, age);
}
}
Restrições de records:
- Não podem estender outras classes e nem ser estendidos.
- Não podem ser
abstract
. - Não podem declarar campos de instância fora da lista do cabeçalho.
O que é permitido:
- Implementar interfaces.
- Declarar campos e métodos
static
.
record Person(String name, int age) {
static int minAge;
static {
minAge = 18;
System.out.println("Static initializer");
}
}
Quando usar records
Records são ideais para representar dados imutáveis, como:
- Resultados de consultas.
- Mensagens de rede.
- Configurações carregadas.
Eles reduzem código repetitivo e melhoram a legibilidade, mantendo segurança e consistência nos dados.
Resumo
- A palavra-chave
record
é usada para declarar um tipo especial de classe imutável. - Permitem criar classes de dados simples com muito menos código que uma classe tradicional.
- Os campos são definidos no cabeçalho e já são privados e finais por padrão.
- O compilador gera automaticamente o construtor canônico, métodos de acesso e as implementações de
equals()
,hashCode()
etoString()
. - É possível personalizar construtores, sobrescrever métodos e adicionar novos comportamentos.
- Não podem herdar de outras classes, serem herdados, ser
abstract
ou ter campos de instância fora do cabeçalho. - Podem implementar interfaces, além de declarar membros e inicializadores estáticos.