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.
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.
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:
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:
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:
E no teste ficaria assim:
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:
JetBrains IDEA
Eclipse Marketplace
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/
Mutio bom...
ResponderExcluir