Skip to content

⚖️ Comparer des objets en Java : Comparable et Comparator

Objectif

Comprendre comment définir et utiliser des ordres de tri personnalisés en Java à l’aide de compareTo() et Comparator.


Pourquoi comparer des objets ?

Certaines structures (comme TreeSet, TreeMap, ou Collections.sort()) ont besoin de savoir comment ordonner les objets.

Deux mécanismes existent : - Comparable → comparaison naturelle, définie dans la classe elle-même. - Comparator → comparaison extérieure, définie hors de la classe.


L’interface Comparable<T>

Elle permet de définir l’ordre naturel d’une classe.

Signature

public interface Comparable<T> {
    int compareTo(T autre);
}

Valeurs possibles

Retour Signification
< 0 L’objet courant est “plus petit” que autre
0 Les deux objets sont égaux
> 0 L’objet courant est “plus grand” que autre

Exemple : tri naturel avec Comparable

class Etudiant implements Comparable<Etudiant> {
    String nom;
    double moyenne;

    Etudiant(String nom, double moyenne) {
        this.nom = nom;
        this.moyenne = moyenne;
    }

    @Override
    public int compareTo(Etudiant autre) {
        return Double.compare(this.moyenne, autre.moyenne);
    }

    @Override
    public String toString() {
        return nom + " (" + moyenne + ")";
    }
}

public class Main {
    public static void main(String[] args) {
        List<Etudiant> liste = List.of(
            new Etudiant("Alice", 82),
            new Etudiant("Bob", 91),
            new Etudiant("Charles", 76)
        );

        List<Etudiant> tri = new ArrayList<>(liste);
        Collections.sort(tri); // utilise compareTo()
        System.out.println(tri);
    }
}

Résultat :

[Charles (76.0), Alice (82.0), Bob (91.0)]


L’interface Comparator<T>

Permet de définir un ordre alternatif, sans modifier la classe.

Signature

public interface Comparator<T> {
    int compare(T o1, T o2);
}

Exemple : tri avec Comparator

class Etudiant {
    String nom;
    double moyenne;
    Etudiant(String nom, double moyenne) { this.nom = nom; this.moyenne = moyenne; }
}

public class Main {
    public static void main(String[] args) {
        List<Etudiant> liste = List.of(
            new Etudiant("Alice", 82),
            new Etudiant("Bob", 91),
            new Etudiant("Charles", 76)
        );

        Comparator<Etudiant> compParNom = Comparator.comparing(e -> e.nom);
        Comparator<Etudiant> compParMoyenneDesc = Comparator.comparingDouble((Etudiant e) -> e.moyenne).reversed();

        List<Etudiant> triNom = new ArrayList<>(liste);
        triNom.sort(compParNom);
        System.out.println("Tri par nom : " + triNom.stream().map(e -> e.nom).toList());

        List<Etudiant> triMoy = new ArrayList<>(liste);
        triMoy.sort(compParMoyenneDesc);
        System.out.println("Tri par moyenne décroissante : " + triMoy.stream().map(e -> e.nom).toList());
    }
}

Résultat :

Tri par nom : [Alice, Bob, Charles]
Tri par moyenne décroissante : [Bob, Alice, Charles]


Différences entre compareTo() et Comparator

Caractéristique Comparable (compareTo) Comparator
Où le définir ? Dans la classe elle-même À l’extérieur de la classe
Nombre de tris possibles 1 seul Illimité
Usage typique Collections.sort(liste) Collections.sort(liste, comp)
Exemple Tri naturel (alphabétique, numérique) Tri personnalisé
Avantage Simplicité, cohérence Flexibilité, externe
Inconvénient Fige l’ordre dans la classe Nécessite un objet externe

Chaînage de comparateurs

Il est possible de combiner plusieurs critères avec thenComparing() :

Comparator<Etudiant> compCombiné =
    Comparator.comparingDouble((Etudiant e) -> e.moyenne).reversed()
              .thenComparing(e -> e.nom);

➡️ Trie d’abord par moyenne décroissante, puis par nom alphabétique.


Utilisation avec TreeSet ou TreeMap

  • Si la classe implémente Comparable, le tri naturel est utilisé.
  • Sinon, on peut passer un Comparator au constructeur.
Set<Etudiant> etudiants = new TreeSet<>(compCombiné);
etudiants.addAll(List.of(
    new Etudiant("Alice", 80),
    new Etudiant("Bob", 80),
    new Etudiant("Charles", 70)
));

➡️ Les éléments sont stockés automatiquement dans l’ordre défini.


Résumé

Situation Solution recommandée
Vous contrôlez la classe et un seul tri est logique Implémentez Comparable
Vous devez trier de plusieurs façons Créez plusieurs Comparator
Vous utilisez TreeSet / TreeMap avec objets non comparables Fournissez un Comparator au constructeur
Vous voulez trier ponctuellement une List list.sort(comp) ou Collections.sort(list, comp)