O Java 14 introduziu uma nova maneira de criar classes chamadas Registros. Neste tutorial, aprenderemos:
- Por que precisamos de Registros Java
- Como criar Registros e usá-los
- Substituindo e estendendo classes de Registros
Leitura recomendada : Recursos do Java 14
Por que precisamos de Registros Java?
Uma das reclamações comuns sobre o Java tem sido sua verbosidade. Se você precisar criar uma classe POJO simples, ela requer o seguinte código de boilerplate.
- Campos privados
- Métodos Getter e Setter
- Construtores
- Métodos hashCode(), equals() e toString().
Esta verbosidade é uma das razões para o grande interesse em Kotlin e Projeto Lombok .
Na verdade, a pura frustração de escrever esses métodos genéricos toda vez levou aos atalhos para criá-los em IDEs Java como Eclipse e IntelliJ IDEA.
Aqui está a captura de tela mostrando a opção da IDE Eclipse para gerar os métodos cerimoniais para uma classe.

Os Registros Java são destinados a remover essa verbosidade, fornecendo uma estrutura compacta para criar as classes POJO.
Como Criar Registros em Java
Registros em Java são uma funcionalidade de pré-visualização, que foi desenvolvida sob JEP 359. Portanto, você precisa de duas coisas para criar Registros em seus projetos Java.
- JDK 14 instalado. Se estiver usando um IDE, ele deve oferecer suporte para o Java 14 também. Tanto o Eclipse quanto o IntelliJ já oferecem suporte para o Java 14, então estamos bem aqui.
- Habilitar a Funcionalidade de Pré-visualização: Por padrão, as funcionalidades de pré-visualização estão desabilitadas. Você pode habilitá-las no Eclipse a partir das configurações do compilador Java do projeto.

Você pode habilitar as funcionalidades de pré-visualização do Java 14 na linha de comando usando a opção --enable-preview -source 14
.
Vamos dizer que eu queira criar uma classe de modelo Employee. Ela ficará algo assim no código a seguir.
package com.journaldev.java14;
import java.util.Map;
public class Employee {
private int id;
private String name;
private long salary;
private Map<String, String> addresses;
public Employee(int id, String name, long salary, Map<String, String> addresses) {
super();
this.id = id;
this.name = name;
this.salary = salary;
this.addresses = addresses;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public long getSalary() {
return salary;
}
public Map<String, String> getAddresses() {
return addresses;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((addresses == null) ? 0 : addresses.hashCode());
result = prime * result + id;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + (int) (salary ^ (salary >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Employee other = (Employee) obj;
if (addresses == null) {
if (other.addresses != null)
return false;
} else if (!addresses.equals(other.addresses))
return false;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (salary != other.salary)
return false;
return true;
}
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", salary=" + salary + ", addresses=" + addresses + "]";
}
}
Ufa, são mais de 70 linhas de código auto-gerado. Agora vamos ver como criar uma classe de Registro de Employee, que basicamente oferece as mesmas funcionalidades.
package com.journaldev.java14;
import java.util.Map;
public record EmpRecord(int id, String name, long salary, Map<String, String> addresses) {
}
Uau, isso não pode ficar mais curto que isso. Já estou adorando as classes de Registro.
Agora, vamos usar o comando javap
para descobrir o que está acontecendo nos bastidores quando um Registro é compilado.
# javac --enable-preview -source 14 EmpRecord.java
Note: EmpRecord.java uses preview language features.
Note: Recompile with -Xlint:preview for details.
# javap EmpRecord
Compiled from "EmpRecord.java"
public final class EmpRecord extends java.lang.Record {
public EmpRecord(int, java.lang.String, long, java.util.Map<java.lang.String, java.lang.String>);
public java.lang.String toString();
public final int hashCode();
public final boolean equals(java.lang.Object);
public int id();
public java.lang.String name();
public long salary();
public java.util.Map<java.lang.String, java.lang.String> addresses();
}
#

# javac —habilitar–visualização –fonte 14 EmpRecord.java
# javap EmpRecord
Se você deseja mais detalhes internos, execute o comando javap com a opção -v.
- A Record class is final, so we can’t extend it.
- # javap -v EmpRecord
- Pontos importantes sobre classes de registro
- As classes de registro estendem implicitamente a classe
java.lang.Record
. - A single constructor is created with all the fields specified in the record definition.
- Todos os campos especificados na declaração do registro são finais.
- Os campos do registro são imutáveis “rasos” e dependem do tipo. Por exemplo, podemos alterar o campo de endereços acessando-o e depois fazendo atualizações nele.
A classe de registro fornece automaticamente métodos acessores para os campos. O nome do método é o mesmo que o nome do campo, não como métodos getters genéricos e convencionais.
A classe de registro também fornece implementações de hashCode(), equals() e toString().
package com.journaldev.java14;
public class RecordTest {
public static void main(String[] args) {
EmpRecord empRecord1 = new EmpRecord(10, "Pankaj", 10000, null);
EmpRecord empRecord2 = new EmpRecord(10, "Pankaj", 10000, null);
Usando Registros em Programa Java
System.out.println(empRecord1);
Vamos dar uma olhada em um exemplo simples de uso da nossa classe EmpRecord.
System.out.println("Name: "+empRecord1.name());
System.out.println("ID: "+empRecord1.id());
// toString()
System.out.println(empRecord1.equals(empRecord2));
// acessando campos
System.out.println(empRecord1 == empRecord2);
}
}
// equals()
EmpRecord[id=10, name=Pankaj, salary=10000, addresses=null]
Name: Pankaj
ID: 10
true
false
// hashCode()
Saída:
O objeto Record funciona da mesma maneira que qualquer classe de modelo, objeto de dados, etc.
public record EmpRecord(int id, String name, long salary, Map<String, String> addresses) {
public EmpRecord {
if (id < 0)
throw new IllegalArgumentException("employee id can't be negative");
if (salary < 0)
throw new IllegalArgumentException("employee salary can't be negative");
}
}
Estendendo o Construtor de Registros
EmpRecord empRecord1 = new EmpRecord(-10, "Pankaj", 10000, null);
Às vezes, queremos ter algumas validações ou logging em nosso construtor. Por exemplo, o id do funcionário e o salário não devem ser negativos. O construtor padrão não terá essa validação. Podemos criar um construtor compacto na classe de registro. O código deste construtor será colocado no início do construtor gerado automaticamente.
Exception in thread "main" java.lang.IllegalArgumentException: employee id can't be negative
at com.journaldev.java14.EmpRecord.<init>(EmpRecord.java:9)
Se criarmos um EmpRecord como o seguinte código:
Vamos obter uma exceção em tempo de execução como:
public record EmpRecord(int id, String name, long salary, Map<String, String> addresses) {
public int getAddressCount() {
if (this.addresses != null)
return this.addresses().size();
else
return 0;
}
}
As Classes de Registros Podem Ter Métodos?
Sim, podemos criar métodos em registros.
Mas, registros são destinados a serem transportadores de dados. Devemos evitar ter métodos de utilidade em uma classe de registro. Por exemplo, o método acima pode ser criado em uma classe de utilidade.
Se você acha que ter um método é essencial para sua classe de Registro, pense cuidadosamente se você realmente precisa de uma classe de Registro?
Source:
https://www.digitalocean.com/community/tutorials/java-records-class