Aujourd’hui je vais vous présenter une classe bien pratique permettant d’implémenter une méthode equals ou compareTo de manière élégante (enfin je trouve).
Guava propose dans sa librairie une classe permettant de faire de chaîner des comparaisons de manière “fluent”.
Généralement, on redéfinit la méthode equals d’une entité afin de pouvoir la rendre comparable.
Pour se faciliter la tâche, on peut avoir recours aux outils fournis pour nos IDEs pour générer rapidement le code nécessaire.
Voila ce que pourrait être le résultat pour la classe MyEntity :
public class MyEntity {
private Long id;
private String name;
private String lastname;
private Date birthday;
private String country;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyEntity myEntity = (MyEntity) o;
if (birthday != null ? !birthday.equals(myEntity.birthday) : myEntity.birthday != null) return false;
if (country != null ? !country.equals(myEntity.country) : myEntity.country != null) return false;
if (id != null ? !id.equals(myEntity.id) : myEntity.id != null) return false;
if (lastname != null ? !lastname.equals(myEntity.lastname) : myEntity.lastname != null) return false;
if (name != null ? !name.equals(myEntity.name) : myEntity.name != null) return false;
return true;
}
On peut constater que le code devient assez verbeux et par conséquent pas très lisible. Bien évidemment la sémantique de la méthode equals() est simple, donc on comprend assez facilement le code.
En aparté : Si l’on envoie à Sonar cette classe dans l’état, celui-ci va râler en vous indiquant que ce n’est pas bien d’écrire des structures conditionnelles sans accolades (et je partage son point de vue 😉 )
Donc pour améliorer la lisibilité (et faire plaisir à Sonar), nous allons, à l’aide de la classe ComparisonChain, clarifier tout ça.
Voila ce que donnerait l’implémentation :
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyEntity myEntity = (MyEntity) o;
return ComparisonChain.start().compare(birthday,myEntity.birthday)
.compare(country, myEntity.country)
.compare(id, myEntity.id)
.compare(lastname,myEntity.lastname)
.compare(name,myEntity.name).result() == 0;
}
Personnellement, je trouve la deuxième version plus claire et plus concise.
La classe ComparisonChain propose un fonctionnement type lazy. C’est à dire que l’évaluation s’arrêtera à la première différence trouvée (même comportement que la première version).
Il faut noter que la classe ComparisonChain ne supporte pas les comparaisons sur les références nulles, néanmoins des champs représentant l’identité d’un objet ne devraient pas être null.
En regardant la documentation, vous trouverez d’autres méthodes permettant d’affiner la comparaison.
#java #guava #comparaison