Publié par
Il y a 10 mois · 3 minutes · Back, Craft, Java / JEE

Améliorations d’API de Comparator dans Java 8

Vous avez sûrement déjà dû développer un comparateur, soit en passant par l’interface Comparable soit par Comparator.

Prenons comme exemple la classe suivante :

class Person {
 String firstName, lastName;
 String getFirstName() { return firstName; }
 String getLastName() { return lastName; }
}

L’API de Comparator

Rappelons que l’interface Comparable<T> est définie ainsi :

int compareTo(T t1, T t2);

Cette méthode retourne un entier :

  • inférieur à 0 si t1 est plus petit que t2
  • égal à 0 si t1 est égal à t2
  • supérieur à 0 si t1 est plus grand que t2

Le comparateur avec l’API classique

Pour déclarer un comparateur classique qui trie des personnes, par exemple, par leur nom puis par leur prénom, nous obtenons un code qui ressemble à ça :

class Person implements Comparable<Person> {
 ...
 int compareTo(Person p1, Person p2) {
  int firstNameCompare = p1.getFirstName().compareTo(p2.getFirstName());
  if( firstNameCompare == 0 ) {
    return p1.getLastName().compareTo(p2.getLastName());
  } else {
    return firstNameCompare;
  }
 }

}

C’est assez verbeux, pas forcement facile à comprendre et ça ne gère que deux champs considérés comme non nuls.

Si on imagine une classe avec plus de champs et si on doit en plus gérer les valeurs nulles, alors le code du comparateur devient beaucoup plus complexe à écrire, comprendre et maintenir.

Le comparateur introduit en Java 8 avec l’API fluent

La classe Comparator a été améliorée en Java 8 pour faciliter la construction de comparateurs de manière déclarative avec une API fluent.

Voyons comment on peut réécrire le comparateur précédant avec la nouvelle API de Java 8 :

Comparator<Person> personComparator = Comparator
 .comparing(Person::getFirstName)
 .thenComparing(Person::getLastName);
On remarque que maintenant le code est plus clair et extensible.

Par défaut, les méthodes comparing et thenComparingextraient le champ à comparer et utilisent la méthode compareTo de la classe du champ extrait pour faire la comparaison.

Ces méthodes sont surchargées pour permettre également la séparation de la fonction d’extraction, de la fonction de comparaison elle-même.

Ceci permet de faire des comparaisons avec une logique différente de celle déclarée par défaut dans la classe (dans la méthode compareTo) :

Imaginons que l’on veuille trier les personnes par nom puis par prénom tout en positionnant en premier les personnes sans nom de famille et en dernier les personnes sans prénom.

Pour simplifier le code, considérons que l’on a un import statique des fonctions présentes dans Comparator.

On aura donc :

comparing(Person::getLastName, nullsFirst(String::compareTo))
.thenComparing(Person::getFirstName, nullsLast(String::compareTo)

Dans cet exemple, la fonction d’extraction est Person::getFirstName tandis que la fonction de comparaison est un comparateur dérivé de nullLast (valeurs nulles a la fin) et si les deux valeurs ne sont pas nulles alors on utilise String::compareTo pour la comparaison.

Si on imagine ajouter l’âge ou une date de naissance a la classe Person, avec la nouvelle API c’est très facile, il suffit d’ajouter l’appel à la méthode comparing/thenComparing au bon endroit selon la priorité désirée pour le champ d’âge ou date de naissance, tandis qu’avec la méthode classique le code devient tout de suite plus complexe et difficile à gérer.

Ces fonctionnalités sont suffisantes pour déclarer la plupart des scénarios de comparaison.

En conclusion, l’API Comparator permet de gérer facilement la plupart des scénarios de comparaison et cela rend l’écriture d’un Comparator beaucoup plus facile.

Une réflexion au sujet de « Améliorations d’API de Comparator dans Java 8 »

  1. Publié par Assem Bardi, Il y a 9 mois

    Pas mal merci

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *