Utilizando o Strategy Design Pattern, é possível reduzir ainda mais a escrita de código para implementar os métodos equals e hashCode, sendo assim, disponibilizei em meu repositório a classe utilitária EqualityStrategy, que como o nome sugere, permite a criação de estratégias para verificar a equivalência de objetos.
Para relembrar, abaixo temos um exemplo padrão de implementação dos métodos equals e hashCode que levam em consideração cada atributo, este código é análogo aos algoritmos gerados pelas IDE's eclipse e NetBeans.
import java.util.Arrays;
class MinhaClasse {
private int atributo1;
private Object atributo2;
private String[] atributo3;
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof MinhaClasse)) {
return false;
}
MinhaClasse other = (MinhaClasse) obj;
if (atributo1 != other.atributo1) {
return false;
}
if (atributo2 == null) {
if (other.atributo2 != null) {
return false;
}
} else if (!atributo2.equals(other.atributo2)) {
return false;
}
if (!Arrays.equals(atributo3, other.atributo3)) {
return false;
}
return true;
}
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + atributo1;
result = prime * result + ((atributo2 == null) ? 0 : atributo2.hashCode());
result = prime * result + Arrays.hashCode(atributo3);
return result;
}
}
Percebam que o código exige bastante atenção quando for realizado uma manutenção, principalmente se a classe for alterada para possuir mais atributos que possam influenciar na computação do equals e hashCode.
Agora um exemplo de implementação de uma classe que utiliza o EqualsUtils e HashCodeUtils para computar o equals e hashCode.
import static br.com.staroski.equality.EqualsUtils.*;
import static br.com.staroski.equality.HashCodeUtils.*;
class MinhaClasse {
private int atributo1;
private Object atributo2;
private String[] atributo3;
public boolean equals(Object object) {
if (this == object) {
return true;
}
if (object instanceof MinhaClasse) {
MinhaClasse that = (MinhaClasse) object;
return equal(this.atributo1, that.atributo1)
&& equal(this.atributo2, that.atributo2)
&& equal(this.atributo3, that.atributo3);
}
return false;
}
public int hashCode() {
int hash = MULTI_FIELD;
hash = hash(hash, atributo1);
hash = hash(hash, atributo2);
hash = hash(hash, atributo3);
return hash;
}
}
Percebam que o código ficou bastante reduzido em relação aos algoritmos gerados pelas IDE's eclipse e NetBeans.
As implementações do equals e hashCode acima, podem ser simplificadas mais ainda, utilizando uma estratégia baseada nos atributos da classe.
Essa estratégia é obtida através da classe EqualityStrategy, disponível em meu repositório, veja o exemplo abaixo para entender:
import static br.com.staroski.equality.EqualityStrategy.*;
class MinhaClasse {
private int atributo1;
private Object atributo2;
private String[] atributo3;
private final EqualityStrategy estrategia = fieldBased(this);
public int hashCode() {
return estrategia.hashCode();
}
public boolean equals(Object object) {
return estrategia.equals(object);
}
}
Percebam que o tamanho do código reduziu drásticamente, o método fieldBased da classe EqualityStrategy, obtém uma estratégia que irá computar o equals e hashCode, utilizando os atributos do objeto passado como parâmetro, neste caso o this. Desta forma, ao sobrescrever os métodos equals e hashCode, basta delegar a chamada para o método da estratégia.