Pular para o conteúdo principal

Java Records

 


Java Records

Imutável, Simples e limpa



Esta funcionalidade da linguagem apareceu pela primeira vez na versão 14 como experimental e assim continuou até a versão 15. Agora liberada de forma definitiva no Java 16.


O objetivo é ser possível ter classes que atuam como portadores transparentes de dados imutáveis. Os registros podem ser considerados tuplas nominais. Ou seja, após criado, um record não pode mais ser alterado.


Records oferece uma uma sintaxe compacta para declarar classes que são portadores transparentes para dados imutáveis superficiais visando reduzir significamente o detalhamento dessas classes e irá melhorar a capacidade de leitura e manutenção do código.


Vamos seguir um exemplo de uma classe chamada Pessoa. O primeiro exemplo vamos utilizar o modo tradicional.


public class Pessoa {

private String nome;
private int idade;

public Pessoa(String nome, int idade) {
super();
this.nome = nome;
this.idade = idade;
}

public String getNome() {
return nome;
}

public void setNome(String nome) {
this.nome = nome;
}

public int getIdade() {
return idade;
}

public void setIdade(int idade) {
this.idade = idade;
}

@Override
public int hashCode() {
return Objects.hash(idade, nome);
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Pessoa other = (Pessoa) obj;
return idade == other.idade && Objects.equals(nome, other.nome);
}

@Override
public String toString() {
return "Pessoa [nome=" + nome + ", idade=" + idade + "]";
}

}


Perceba que a classe possui apenas dois atributos (nome e idade). Geramos os métodos getters e setters, equals, hashCode e toString. Também um construtor para facilitar a criação do objeto. A classe ficou com mais de 50 linhas.


Agora vamos implementar um teste simples para esta classe, verificando as suas “funcionalidades”. Geralmente não testamos este tipo de classe quando não existe regra de negócio envolvida. E também existem bibliotecas que facilitam esta tarefa caso queira garantir que ninguém irá escrever regra de negócio no get e set.


class PessoaTest {

@Test
void testGetNome() {
Pessoa pessoa = new Pessoa("Java", 25);

assertEquals("Java", pessoa.getNome());
}

@Test
void testSetNome() {
Pessoa pessoa = new Pessoa();
pessoa.setNome("Java");

assertEquals("Java", pessoa.getNome());
}

@Test
void testGetIdade() {
Pessoa pessoa = new Pessoa("Java", 25);

assertEquals(25, pessoa.getIdade());
}

@Test
void testSetIdade() {
Pessoa pessoa = new Pessoa();
pessoa.setIdade(25);

assertEquals(25, pessoa.getIdade());
assertNull(pessoa.getNome());
}

@Test
void testEqualsObject() {
Pessoa pessoa1 = new Pessoa("Java", 25);
Pessoa pessoa2 = new Pessoa("Java", 25);

assertEquals(pessoa1, pessoa2);
}

@Test
void testHashCode() {
Pessoa pessoa1 = new Pessoa("Java", 25);
Pessoa pessoa2 = new Pessoa("Java", 25);

assertEquals(pessoa1.hashCode(), pessoa2.hashCode());

}

@Test
void testToString() {
Pessoa pessoa = new Pessoa("Java", 25);
assertEquals("Pessoa [nome=Java, idade=25]", pessoa.toString());
}



Todos os testes passando.


Agora vamos transformar a classe em record e verificar se todos os testes continuam funcionando.


Iniciando o refactor, vamos trocar a palavra chave class por record e excluir todo o restante do conteúdo. Isso mesmo, deixe a “classe” como no exemplo abaixo:


public record Pessoa(String nome, int idade) {

}


Agora vejamos nosso teste quebrado, que na verdade nem compila mais pois não temos os métodos getters, setters e o construtor sem parâmetros. Abaixo um dos erros de compilação:


java: cannot find symbol

  symbol:   method getNome()

  location: variable pessoa of type com.giacom.Pessoa



A primeira alteração na classe de teste é trocar os métodos getters pelo nome do atributo, pois o tipo record oferece acesso somente pelo nome do atributo, então apenas trocamos o getNome por nome por exemplo.


Agora a classe de testes possui alguns erros referentes ao construtor sem parâmetros e os métodos setters. Como vimos anteriormente, records são imutáveis, então não pode ser alterada posteriormente a sua criação e por isso não faz sentido termos estes tipos de método.


O que pode ser feito neste caso então? Simples, apenas remova este tipo de teste de métodos setter, pois não teremos mais. E quanto ao construtor default? Isso deve ser analisado a cada necessidade, pois não há como setar estas informações posteriormente. E com um pequeno ajuste no teste toString(), nossos testes estão passando.




Mas ainda é possível ter um construtor para poder manipular algum dado por exemplo:


public record Pessoa3(String nome) {

  public Pessoa3 {
      nome = nome.toUpperCase();
  }

}


Independente do valor passado (desde que não seja nulo), sempre será transformado em maiúsculo. Um construtor sem parâmetros também pode ser utilizado, porém ele deve chamar outro construtor para preencher os demais atributos:


public record Pessoa(String nome, int idade) {

  public Pessoa {
      Objects.nonNull(nome);
  }

  public Pessoa(String nome) {
      this(nome, 0);
  }

  public Pessoa() {
      this("Indefinido", 0);
  }

}


E no teste ficaria assim:


@Test
void testNovaPessoa() {
  Pessoa pessoa = new Pessoa();
  assertEquals("Indefinido", pessoa.nome());
  assertEquals(0, pessoa.idade());
}



E sobre os métodos equals, hashCode e toString? O Records gera automaticamente estes métodos para nós.


Abaixo algumas restrições referentes a este tipo de classe:


  • Uma Record class não possui uma cláusula extends

  • Uma Record class não pode ser abstrata

  • Os atributos derivados da classe Record são todos finais

  • Não pode declarar campos de instância

  • Não pode declarar métodos nativos


Além das restrições acima, uma classe de registro se comporta como uma classe normal:


  • Uma instância de Record é criada com a expressão new

  • Pode ser declarada como um tipo genérico

  • Pode declarar métodos, atributos e inicializadores estáticos

  • Pode declarar métodos de instância

  • Pode implementar interfaces

  • Utilizar annotations

  • Podem ser serializados e desserializado



Todas as classes do tipo Record estendem da classe abstrata java.lang.Record 


Reflection API

Foram adicionados dois novos métodos na classe java.lang.Class:

  • RecordComponent [] getRecordComponents () - Retorna uma matriz de objetos java.lang.reflect.RecordComponent. Os elementos deste array correspondem aos componentes de uma instância do tipo Record, na mesma ordem em que aparecem na declaração. Informações adicionais podem ser extraídas de cada elemento da matriz, incluindo seu nome, anotações e método de acesso.

  • boolean isRecord () - Retorna verdadeiro se a classe fornecida foi declarada como um Record. (Comparado ao isEnum.)


Records vs Lombok

O uso de Lombok sempre é uma polêmica. Alguns desenvolvedores amam e outros odeiam. Os Records não substituem o Lombok, pois embora forneçam muitos recursos interessantes e sejam organizados no código, o Lombok ainda tem muito mais recursos do que Records, por exemplo o @Builder

Para mim a vantagem dos Records é que ele é nativo da linguagem e não é necessário utilizar uma biblioteca de terceiros, trazendo mais facilidade para os desenvolvedores. O Frameworks e outras bibliotecas irão se adaptar com o tempo. É possível utilizar o Lombok com Records, porém deve ser usado com cuidado.

Mãos na massa

Caso queira experimentar o Java 16, ele pode ser baixado através do site da Oracle e também do projeto AdoptOpenJDK.

As IDE’s que tem suporte até o momento:

Deixe nos comentários se já está utilizando este recurso. Um abraço e até a próxima!

Referências:

https://openjdk.java.net/jeps/395
https://www.baeldung.com/java-record-keyword
https://angiejones.tech/deserializing-api-responses-into-java-records/
https://medium.com/@gaozhixiang/records-vs-lombok-in-java-15-193306340ca0
https://softwaregarden.dev/en/posts/new-java/records/vs-lombok/

Comentários

Postagens mais visitadas deste blog

Certificação Java 11 - O que mudou

Certificação Java 11 - O que mudou A Oracle liberou recentemente uma atualização das suas certificações Java para atender a nova versão Java 11  LTS (Long Term Support) . Mas o que muda em relação a certificação Java 8? Preciso me atualizar? Por onde começo?  Neste post, vamos responder estas e outras questões sobre essa nova série de certificações. Caso você não tenha acompanhado a série sobre certificação, recomendo a leitura dos posts anteriores: https://www.guiadojava.com.br/2018/06/guia-da-certificacao-java-se-8.html Também temos um bate papo com os maiores especialistas de Java do mercado. Assista o replay aqui: https://events.genndi.com/replay/169105139238448348/23a5b3a7b0/0/83729443273C Nomenclatura e requisitos A partir de agora, você não receberá o certificado se fizer apenas a primeira prova, como era no Java 8 (1Z0-808 - Java SE 8 Programmer I). Você terá que fazer duas provas para obter o certificado " Oracle Certified Professional: Java SE 11 Dev

Java 15 - Novidades (ou não)

Java 15 - Novidades (ou não) O Java 15 já está em fase de testes com as suas features fechadas (Rampdown Phase One). Isso quer dizer que mais nenhuma feature será implementada. Teremos melhorias em funcionalidades já liberadas para testes e outras consolidadas agora nesta versão, mas nada de grandes mudanças. Porém é sempre bom ficar atualizado não é? Para acompanhar os builds e agenda da liberação, acesse esta página . Revisando o processo de versionamento Com o lançamento do  Java 9 em 2017 , o cronograma de lançamento do Java mudou, de um lançamento principal a cada  3 anos ou mais  para um lançamento a cada  seis meses . Um dos principais motivos dessa alteração foi oferecer aos desenvolvedores acesso mais rápido as melhorias contínuas. Os lançamentos ocorrem em  Março  e  Setembro  de cada ano. Ainda cabe um post específico para o modelo de versionamento para explicar sobre as versões LTS, versões intermediárias e funcionalidades " preview ". Para mais informações, veja

Guia da certificação Java SE 8 Programmer l - Parte 1: Conhecendo a certificação

Seja bem-vindo a série de postagens sobre a certificação Java. Como funciona, o que fazer para comprar, marcar o dia da prova e o principal, o que estudar. Para ver o índice da série e as datas das publicações, acesse este link Parte 1 – Conhecendo a certificação Nesta primeira parte, vamos navegar pelo site da Oracle Education e da Pearson VUE para conhecer como funciona a certificação e se ambientar. Ambos os site estão em Inglês e como já dito no índice da série, a prova não tem opção em português. Site da Oracle O site da Oracle não é um dos melhores em usabilidade. Então se procurar por certificação Java no Google, irá encontrar diversos cursos, livros e blogs falando a respeito da certificação menos o site da Oracle. Pois bem, abaixo o link direto para informações do exame 1Z0-808 - Java SE 8 Programmer I https://education.oracle.com/pls/web_prod-plq-dad/db_pages.getpage?page_id=5001&get_params=p_exam_id:1Z0-808 Neste link você encontrará