CodeGym/Blog Java/Random-FR/La classe Comparator de Java
Auteur
Artem Divertitto
Senior Android Developer at United Tech

La classe Comparator de Java

Publié dans le groupe Random-FR
membres
Salut! Aujourd'hui, nous allons parler de la comparaison d'objets. Classe comparateur de Java - 1 Hmm... Mais n'avons-nous pas déjà parlé de ce sujet plus d'une fois ? :/ Nous connaissons le ==fonctionnement de l'opérateur, ainsi que les méthodes equals()et hashCode(). La comparaison est un peu différente. Auparavant, nous voulions probablement dire "vérifier l'égalité des objets". Mais les raisons de comparer des objets entre eux peuvent être complètement différentes ! Le plus évident d'entre eux est le tri. Je pense que si on vous disait de trier ArrayList<>des nombres ou des chaînes, vous seriez capable de gérer cela sans aucun problème:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       String name1 = "Masha";
       String name2 = "Sasha";
       String name3 = "Dasha";

       List<String> names = new ArrayList<>();
       names.add(name1);
       names.add(name2);
       names.add(name3);

       Collections.sort(names);
       System.out.println(names);
   }
}
Sortie console:
[Dasha, Masha, Sasha]
Si vous vous souvenez de la Collectionsclasse et de sa sort()méthode, bravo ! Je pense que vous n'aurez également aucun problème avec les chiffres. Voici une tâche plus difficile pour vous :
public class Car {

   private int manufactureYear;
   private String model;
   private int maxSpeed;

   public Car(int manufactureYear, String model, int maxSpeed) {
       this.manufactureYear = manufactureYear;
       this.model = model;
       this.maxSpeed = maxSpeed;
   }

   // ...getters, setters, toString()

}

import java.util.ArrayList;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       List<Car> cars = new ArrayList<>();

       Car ferrari = new Car(1990, "Ferrari 360 Spider", 310);
       Car lambo = new Car(2012, "Lamborghini Gallardo", 290);
       Car bugatti = new Car(2010, "Bugatti Veyron", 350);

       cars.add(ferrari);
       cars.add(bugatti);
       cars.add(lambo);
   }
}
La tâche est en fait simple. Nous avons une Carclasse et 3 objets Car. Pourriez-vous trier les voitures dans la liste ? Vous vous demanderez probablement : "Comment doivent-ils être triés ?" De nom? Par année de fabrication ? Par vitesse maximale? Excellente question. Pour le moment, nous ne savons pas comment trier les Carobjets. Et, tout naturellement, Java ne le sait pas non plus ! Lorsque nous essayons de passer une liste d' Carobjets à la Collections.sort()méthode, nous obtenons une erreur :
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       List<Car> cars = new ArrayList<>();

       Car ferrari = new Car(1990, "Ferrari 360 Spider", 310);
       Car lambo = new Car(20012, "Lamborghini Gallardo", 290);
       Car bugatti = new Car(2010, "Bugatti Veyron", 350);

       cars.add(ferrari);
       cars.add(bugatti);
       cars.add(lambo);

       // Compilation error!
       Collections.sort(cars);
   }
}
Et en effet, comment le langage saurait-il trier les objets des classes que vous avez écrites ? Cela dépend de ce que votre programme doit faire. Il faut en quelque sorte apprendre à Java à comparer ces objets. Et de les comparer comme on veut. Java a un mécanisme spécial pour cela : l' Comparableinterface. Afin de comparer et de trier d'une manière ou d'une autre nos Carobjets, la classe doit implémenter cette interface, qui consiste en une seule méthodecompareTo() :
public class Car implements Comparable<Car> {

   private int manufactureYear;
   private String model;
   private int maxSpeed;

   public Car(int manufactureYear, String model, int maxSpeed) {
       this.manufactureYear = manufactureYear;
       this.model = model;
       this.maxSpeed = maxSpeed;
   }

   @Override
   public int compareTo(Car o) {
       return 0;
   }

   // ...getters, setters, toString()

}
Veuillez noterque nous avons spécifié l' Comparable<Car>interface, pas seulement Comparable. Il s'agit d'une interface paramétrée, c'est-à-dire que nous devons spécifier la classe spécifique associée. En principe, vous pouvez supprimer <Car>de l'interface, mais la comparaison sera alors basée sur Objectdes objets par défaut. Au lieu de la compareTo(Car o)méthode, notre classe aura :
@Override
   public int compareTo(Object o) {
       return 0;
   }
Bien sûr, il est beaucoup plus facile pour nous de travailler avec Car. À l'intérieur de la compareTo()méthode, nous implémentons notre logique pour comparer les voitures. Supposons que nous ayons besoin de les trier par année de fabrication. Vous avez probablement remarqué que la compareTo()méthode renvoie un int, pas un boolean. Ne laissez pas cela vous surprendre. Quand on compare deux objets, il y a 3 possibilités :
  • а < b
  • a > b
  • a == b.
booleann'a que 2 valeurs : vrai et faux, ce qui ne fonctionne pas bien pour comparer des objets. Avec int, tout est beaucoup plus simple. Si la valeur de retour est > 0, alors a > b. Si le résultat de compareToest < 0, alors a < b. Et, si le résultat est == 0, alors deux objets sont égaux : a == b. Enseigner à notre classe à trier les voitures par année de fabrication est facile :
@Override
public int compareTo(Car o) {
   return this.getManufactureYear() - o.getManufactureYear();
}
Mais que se passe-t-il ici ? Nous prenons un objet Voiture ( this), obtenons l'année de fabrication de cette voiture et en soustrayons l'année de fabrication d'une autre voiture (celle avec laquelle l'objet est comparé). Si l'année de fabrication de la première voiture est supérieure, la méthode renverra un int > 0. Cela signifie que la this car >voiture o. Inversement, si l'année de fabrication de la deuxième voiture ( о) est supérieure, la méthode renverra un nombre négatif, ce qui signifie que o > this. Enfin, s'ils sont égaux, la méthode retournera 0. Ce mécanisme simple nous suffit déjà pour trier des collections d' Carobjets ! Vous n'avez rien d'autre à faire. Vérifiez-le:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       List<Car> cars = new ArrayList<>();

       Car ferrari = new Car(1990, "Ferrari 360 Spider", 310);
       Car lambo = new Car(2012, "Lamborghini Gallardo", 290);
       Car bugatti = new Car(2010, "Bugatti Veyron", 350);

       cars.add(ferrari);
       cars.add(bugatti);
       cars.add(lambo);

       // There was previously an error here
       Collections.sort(cars);
       System.out.println(cars);
   }
}
Sortie console:
[Car{manufactureYear=1990, model='Ferrari 360 Spider', maxSpeed=310},
Car{manufactureYear=2010, model='Bugatti Veyron', maxSpeed=350},
Car{manufactureYear=2012, model='Lamborghini Gallardo', maxSpeed=290}]
Les voitures sont triées comme on veut ! :) Classe comparateur de Java - 2Quand dois-je utiliser Comparable? La méthode de comparaison implémentée dans Comparables'appelle l'ordre naturel. En effet, dans la compareTo()méthode, vous définissez la manière la plus courante, ou la plus naturelle, de comparer les objets de cette classe. Java a déjà un ordre naturel. Par exemple, Java sait que les chaînes sont le plus souvent triées par ordre alphabétique et les nombres par valeur numérique croissante. Par conséquent, si vous appelez la sort()méthode sur une liste de nombres ou de chaînes, ils seront triés. Si notre programme compare et trie généralement les voitures par année de fabrication, nous devons définir le tri naturel des voitures à l'aide de l' Comparable<Car>interface et de lacompareTo()méthode. Et si cela ne nous suffisait pas? Imaginons que notre programme ne soit pas si simple. Dans la plupart des cas, le tri naturel des voitures (que nous avons paramétré pour être effectué par année de fabrication) nous convient. Mais parfois nos clients sont des aficionados de la conduite rapide. Si nous préparons un catalogue de voitures à consulter, les voitures doivent être triées par vitesse maximale. Classe comparateur de Java - 3Par exemple, supposons que nous devions trier ainsi 15 % du temps. Cela ne nous suffit évidemment pas pour définir le Cartri naturel de la classe par vitesse et non par année de fabrication. Mais nous ne pouvons pas ignorer 15 % de nos clients. Alors que faisons-nous? Une autre interface nous vient ici en aide : Comparator. Tout comme Comparable, c'est une interface paramétrée. Quelle est la différence? Comparablerend nos objets « comparables » et définit leur ordre de tri le plus naturel, c'est-à-dire l'ordre de tri qui sera utilisé dans la plupart des cas. Comparatorest une interface de "comparaison" distincte. Si nous devons implémenter une sorte d'ordre de tri spécial, nous n'avons pas besoin d'aller dans la Carclasse et de changer la logique de compareTo(). Au lieu de cela, nous pouvons créer une classe distincte qui implémente Comparator et lui apprendre à effectuer le tri dont nous avons besoin !
import java.util.Comparator;

public class MaxSpeedCarComparator implements Comparator<Car> {

   @Override
   public int compare(Car o1, Car o2) {
       return o1.getMaxSpeed() - o2.getMaxSpeed();
   }
}
Comme vous pouvez le voir, notre Comparatorest assez simple. Nous n'avons besoin d'implémenter qu'une seule méthode d'interface : compare(). Il prend deux Carobjets en entrée et compare leurs vitesses maximales de la manière habituelle (par soustraction). Comme compareTo(), il renvoie le an int, et le principe de comparaison est le même. Comment utilisons-nous cela? Tout est simple :
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       List<Car> cars = new ArrayList<>();

       Car ferrari = new Car(1990, "Ferrari 360 Spider", 310);
       Car lambo = new Car(2012, "Lamborghini Gallardo", 290);
       Car bugatti = new Car(2010, "Bugatti Veyron", 350);

       cars.add(ferrari);
       cars.add(bugatti);
       cars.add(lambo);

       Comparator speedComparator = new MaxSpeedCarComparator();
       Collections.sort(cars, speedComparator);

       System.out.println(cars);
   }
}
Sortie console:
[Car{manufactureYear=2012, model='Lamborghini Gallardo', maxSpeed=290},
Car{manufactureYear=1990, model='Ferrari 360 Spider', maxSpeed=310},
Car{manufactureYear=2010, model='Bugatti Veyron', maxSpeed=350}]
Nous créons simplement un objet comparateur et le transmettons à la Collections.sort()méthode avec la liste à trier. Lorsque la sort()méthode reçoit un comparateur, elle n'utilise pas le tri naturel défini dans la méthode Carde la classe compareTo(). Au lieu de cela, il applique l'algorithme de tri défini par le comparateur qui lui est transmis. Quels sont les avantages de faire cela? Tout d'abord, la compatibilité avec le code existant. Nous avons créé une nouvelle méthode de tri spéciale, tout en conservant celle existante qui sera utilisée la plupart du temps. Nous n'avons pas Cardu tout touché à la classe. C'était un Comparable, et il reste donc :
public class Car implements Comparable<Car> {

   private int manufactureYear;
   private String model;
   private int maxSpeed;

   public Car(int manufactureYear, String model, int maxSpeed) {
       this.manufactureYear = manufactureYear;
       this.model = model;
       this.maxSpeed = maxSpeed;
   }

   @Override
   public int compareTo(Car o) {
       return this.getManufactureYear() - o.getManufactureYear();
   }

   // ...getters, setters, toString()

}
Deuxièmement, la flexibilité. Nous pouvons ajouter autant d'algorithmes de tri que nous le souhaitons. Par exemple, nous pouvons trier les voitures par couleur, vitesse, poids ou par combien de fois une voiture a été utilisée dans les films Batman. Tout ce que nous avons à faire est de créer un fichier Comparator. C'est ça! Aujourd'hui, vous avez étudié deux mécanismes très importants que vous utiliserez souvent dans de vrais projets au travail. Mais, comme vous le savez, la théorie sans la pratique n'est rien. Il est maintenant temps de consolider vos connaissances et d'effectuer certaines tâches !
Commentaires
  • Populaires
  • Nouveau
  • Anciennes
Tu dois être connecté(e) pour laisser un commentaire
Cette page ne comporte pas encore de commentaires