JavaRush /Blog Java /Random-FR /Comparateur en Java

Comparateur en Java

Publié dans le groupe Random-FR
Bonjour! Aujourd'hui, nous allons parler de comparer des objets. Hmm... Mais il semble qu'on en ait déjà parlé plus d'une fois ? :/ Nous savons comment ==fonctionne l'opérateur « », ainsi que les méthodes equals()et hashCode(). La comparaison n’est pas vraiment là. Auparavant, nous parlions plutôt de « tester l'égalité des objets ». Comparateur en Java - 1Mais comparer des objets entre eux peut avoir des objectifs complètement différents ! Le plus évident est le tri. Je pense que si on vous demande de trier une liste de ArrayList<>nombres ou de chaînes, vous pouvez le gérer sans 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 = "Даша";

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

       Collections.sort(names);
       System.out.println(names);
   }
}
Sortie de la console :

[Даша, Маша, Саша]
C'est bien si vous vous souvenez du cours Collectionset de sa méthode sort(). Je ne pense pas non plus qu’il y aura de problèmes de 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;
   }

   //...геттеры, сеттеры, 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);
   }
}
C’est très simple : une classe Caret 3 de ses objets. Ayez la gentillesse de trier les voitures dans la liste ! Vous vous demanderez probablement : « Comment les trier ? Par nom, par année de fabrication, par vitesse maximale ? Excellente question. Nous ne savons pas pour l'instant comment trier les objets de la classe Car. Et, tout naturellement, Java ne le sait pas non plus ! Lorsque nous essayons de transmettre Collections.sort()une liste d'objets à une méthode Car, nous recevrons 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);

       //ошибка компилятора!
       Collections.sort(cars);
   }
}
Et vraiment, comment le langage sait-il exactement comment trier les objets que vous écrivez ? Cela dépend des objectifs de votre programme. Nous devons en quelque sorte apprendre à Java à comparer ces objets. Et comparez la façon dont nous en avons besoin. À cet effet, Java dispose d'un outil spécial - interface Comparable. En anglais, cela se traduit par « comparable ». Pour que nos objets Carpuissent être comparés les uns aux autres et triés d'une manière ou d'une autre, la classe doit implémenter cette interface et implémenter sa seule méthode :compareTo() :
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;
   }

   //...геттеры, сеттеры, toString()

}
Faites attention:nous avons spécifié l'interface Comparable<Car>, pas seulement Comparable. Il s'agit d'une interface typée, c'est-à-dire qu'elle nécessite de spécifier la classe spécifique à laquelle elle est associée. En principe, <Car>vous pouvez le supprimer de l'interface, mais il compare ensuite les objets par défaut Object. Au lieu d'une méthode compareTo(Car o)dans notre classe nous aurons :
@Override
   public int compareTo(Object o) {
       return 0;
   }
Bien sûr, il est beaucoup plus facile pour nous de travailler avec Car. Dans la méthode compareTo(), nous implémentons la logique de comparaison des machines. Disons que nous devons les trier par année de fabrication. Vous avez probablement remarqué que la méthode compareTo()renvoie la valeur int, et non boolean. Ne vous laissez pas surprendre. Le fait est que comparer deux objets nous donne 3 options possibles :
  • а < b
  • a > b
  • a == b.
Il booleann'a que 2 valeurs - vrai et faux, ce qui n'est pas pratique pour comparer des objets. Tout est intbeaucoup plus simple. Si la valeur de retour > 0est , alors a > b. Si le résultat compareTo < 0est , alors а < b. Eh bien, si le résultat est == 0, alors les deux objets sont égaux : a == b. Apprendre à notre classe à trier les voitures par année de fabrication est aussi simple que d’éplucher des poires :
@Override
public int compareTo(Car o) {
   return this.getManufactureYear() - o.getManufactureYear();
}
Que se passe t-il ici? On prend un objet automobile ( this), l'année de fabrication de cette voiture, et on en soustrait l'année de fabrication d'une autre voiture (celle avec laquelle on compare l'objet). Si l’année de fabrication de la première voiture est supérieure, la méthode reviendra int > 0. Ce qui veut dire qu'une voiture this >est une voiture о. Si au contraire l’année de fabrication de la deuxième voiture ( о) est supérieure, alors la méthode retournera un nombre négatif, et donc о > this. Eh bien, s’ils sont égaux, la méthode renverra 0. Un mécanisme aussi simple suffit déjà à trier des collections d'objets Car! Vous n'avez rien d'autre à faire. Te voilà:
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);

       //тут раньше была ошибка
       Collections.sort(cars);
       System.out.println(cars);
   }
}
Sortie de la 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 il se doit ! :) Comparateur en Java - 2Dans quels cas faut-il l'utiliser Comparable? La méthode de comparaison mise en œuvre Comparableest appelée « ordre naturel ». En effet, dans la méthode, compareTo()vous décrivez la méthode de comparaison la plus courante qui sera utilisée pour les objets de cette classe dans votre programme. Natural Ordering est déjà présent en Java. Par exemple, Java sait que les chaînes sont le plus souvent triées par ordre alphabétique et que les nombres sont le plus souvent triés par valeur ascendante. Par conséquent, si vous appelez la méthode sur une liste de nombres ou de chaînes sort(), ils seront triés. Si dans notre programme les voitures sont dans la plupart des cas comparées et triées par année de fabrication, alors il vaut la peine de définir un tri naturel pour elles à l'aide de l'interface Comparable<Car>et de la méthode compareTo(). Mais que se passe-t-il si cela ne nous suffit pas ? Imaginons que notre programme ne soit pas si simple. Dans la plupart des cas, le tri naturel des voitures (nous le fixons par année de fabrication) nous convient. Mais parfois, parmi nos clients, il y a des adeptes de la conduite rapide. Si nous préparons un catalogue de voitures parmi lesquelles choisir, elles doivent être classées par vitesse maximale. Comparateur en Java - 3Par exemple, nous avons besoin d’un tel tri dans 15 % des cas. Ce n’est clairement pas suffisant pour établir un tri naturel Carpar vitesse plutôt que par année de fabrication. Mais on ne peut pas ignorer 15 % des clients. Qu'est-ce qu'on fait? Ici, une autre interface vient à notre aide - Comparator. Tout comme, Comparablec'est tapé. Quelle est la différence? Comparablerend nos objets "comparables" et crée pour eux l'ordre de tri le plus naturel qui sera utilisé dans la plupart des cas. Comparator- il s'agit d'une classe « comparateur » distincte (la traduction est un peu maladroite, mais compréhensible). Si nous devons implémenter un tri spécifique, nous n'avons pas besoin d'entrer dans la classe Caret de changer la logique compareTo(). Au lieu de cela, nous pouvons créer une classe de comparaison distincte dans notre programme et lui apprendre à faire 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 constater, le nôtre Comparatorest assez simple. Il n'y a qu'une seule méthode compare()- c'est une méthode d'interface Comparatorqui doit être implémentée. Il prend deux objets en entrée Caret compare leur vitesse maximale de la manière habituelle (par soustraction). Comme compareTo(), il renvoie le nombre int, le principe de comparaison est le même. Comment pouvons-nous utiliser cela ? Très 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 de la 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 méthode Collections.sort()avec la liste à trier. Ayant reçu un comparateur en entrée, la méthode sort()n'utilisera pas le tri naturel défini dans la méthode compareTo()de classe Car. Au lieu de cela, il appliquera l'algorithme de tri du comparateur qui lui est transmis. Quels avantages cela nous apporte-t-il ? Premièrement, la compatibilité avec le code écrit. Nous avons créé une nouvelle méthode de tri spécifique, tout en conservant celle actuelle, qui sera utilisée dans la plupart des cas. Nous n'avons pas touché du tout à la classe Car. Il Comparableest resté tel qu'il était :
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();
   }

   //...геттеры, сеттеры, toString()

}
Deuxièmement, la flexibilité. Nous pouvons ajouter autant de sortes que nous le souhaitons. Par exemple, triez les voitures par couleur, vitesse, poids ou combien de fois la voiture a été utilisée dans les films Batman. Il suffit simplement d'en créer un supplémentaire Comparator. C'est tout! Aujourd'hui, vous avez appris 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 donc temps de consolider vos connaissances et de résoudre plusieurs problèmes ! :)
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION