Melhorando a sobrescrita dos métodos equals() e hashCode()

Olá hoje iremos melhorar a forma que realizamos uma tarefa que muitos desenvolvedores não gostam de fazer, ou até mesmo deixam de lado, mas é de extrema importância para o correto funcionamento dos nossos Objetos, que é a sobrescrita dos métodos equals e hashCode().

Sobrescrita utilizando uma IDE


A maioria das IDEs realizam a tarefa de sobrescrever os métodos equals(Object o) e hashCode(), mas o código gerado não é dos melhores, vamos analisar um exemplo da geração automática usando a IDE Eclipse, segue o código:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class Cliente {

 private String cpf;
 
 public Cliente(String cpf) {
  this.cpf = cpf;
 }

 public String getCpf() {
  return cpf;
 }

 @Override
 public int hashCode() {
  final int prime = 31;
  int result = 1;
  result = prime * result + ((cpf == null) ? 0 : cpf.hashCode());
  return result;
 }

 @Override
 public boolean equals(Object obj) {
  if (this == obj)
   return true;
  if (obj == null)
   return false;
  if (getClass() != obj.getClass())
   return false;
  Cliente other = (Cliente) obj;
  if (cpf == null) {
   if (other.cpf != null)
    return false;
  } else if (!cpf.equals(other.cpf))
   return false;
  return true;
 }
}

O código acima esta bem poluído, porque a IDE adiciona vários blocos condicionais para garantir a integridade dos métodos, para confirma o funcionamento vamos criar um caso de teste usando JUnit:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class ClienteTest{
 
 @Test
 public void equalsClienteTest(){
  
  Cliente cliente  = new Cliente("9876543210");
  Cliente cliente2 = new Cliente("9876543210");

  Assert.assertEquals(cliente, cliente2);
 }
 
 @Test
 public void notEqualsClienteTest(){
  
  Cliente cliente  = new Cliente("0123456789");
  Cliente cliente2 = new Cliente("9876543210");

  Assert.assertNotEquals(cliente, cliente2);
 }
 
 @Test
 public void leftNullEqualsClienteTest(){
  
  Cliente cliente  = new Cliente(null);
  Cliente cliente2 = new Cliente("9876543210");

  Assert.assertNotEquals(cliente, cliente2);
 }

 @Test
 public void rightNullEqualsClienteTest(){
  
  Cliente cliente  = new Cliente("0123456789");
  Cliente cliente2 = new Cliente(null);

  Assert.assertNotEquals(cliente, cliente2);
 }
}

Ao executar o teste, podemos notar que nossa implementação esta correta, porém a escrita do código pode melhorar.

Sobrescrita usando a classe java.util.Objects


A classe java.util.Objects possui uma porção de métodos utilitários que ajudam na manipulação de objetos variados, esta classe esta disponível a partir do Java 7, vamos analisar como esta classe pode nos ajudar a melhorar a sobrescrita do método equals(Object o) e hasCode():


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class Cliente {

 private String cpf;
 
 public Cliente(String cpf) {
  this.cpf = cpf;
 }

 public String getCpf() {
  return cpf;
 }
 
 @Override
 public int hashCode(){
  return Objects.hash(this.cpf);
 }

 @Override
 public boolean equals(Object obj){
  
  if(Objects.nonNull(obj) && getClass() != obj.getClass()){
   return false;
  }
  else{
   final Cliente other = (Cliente) obj;
         
         return Objects.equals(this.cpf, other.cpf);
  }
 }
}

Executando o JUnit novamente, todos os casos de testes são executados com sucesso, e podemos notar um código bem mais limpo e simples, isso porque estamos usando os métodos Objects.hash e Objects.equals que ajudam na escrita das implementações do hashcode e equals.

Melhorando ainda mais seu Código


Mesmo usando a classe java.util.Objects,  nossa classe ainda possui um código muito vinculado a sua infraestrutura, com isso temos o famoso código boilerplate, que é aquele código repetitivo que temos que criar em todas as classes do nosso domínio, exemplo:
  • Construtores;
  • Getters e Setters;
  • hashCode();
  • equals(Object o);
  • toString().
Para melhorar isso existem uma porção de APIs e Frameworks que podem gerenciar esse tipo de tarefa:

Comentários

Popular Posts

Criando arquivos de log com Log4J

Monitorando o Tomcat com Java VisualVM

Injeção de dependências em Java EE usando @Inject, @EJB e @Resource ?

Gerenciamento de Transações com EJB - Parte 2

AngularJS - Formatando Datas com o Filter Date

JBoss AS 7 - Instalação e Configuração

Configurando o arquivo application.properties do SpringBoot

Métodos Utilitários da Classe String

Criando Módulos e DataSources no Wildfly

Criando uma Aplicação com Spring Boot e MongoDB