web-dev-qa-db-fra.com

Quand utiliser Comparable et Comparator

J'ai une liste d'objets que je dois trier sur un champ, par exemple Score. Sans trop y penser, j'ai écrit une nouvelle classe qui implémente Comparator, qui effectue la tâche et fonctionne. 

En regardant maintenant, je me demande si je devrais plutôt avoir ma classe implémenter Comparable au lieu de créer une nouvelle classe qui implémente Comparator. La partition est le seul champ sur lequel les objets seront classés. 

  1. Qu'est-ce que j'ai fait acceptable comme pratique? 

  2. La bonne approche est-elle "Tout d'abord, demandez à la classe d'implémenter Comparable (pour l'ordre naturel) et si une comparaison de champ alternative est requise, créez une nouvelle classe qui implémente Comparator"?

  3. Si (2) ci-dessus est vrai, cela signifie-t-il que l'on doit implémenter Comparator uniquement après que la classe a implémenté Comparable? (En supposant que je possède la classe d'origine).

96
pkrish

Je dirais qu'un objet doit implémenter Comparable si c'est la façon naturelle et claire de trier la classe, et quiconque aurait besoin de trier la classe voudrait généralement le faire de cette façon.

Si, toutefois, le tri était une utilisation inhabituelle de la classe ou si le tri n'avait de sens que pour un cas d'utilisation spécifique, un comparateur serait alors une meilleure option.

En d'autres termes, étant donné le nom de la classe, est-il clair que le sort serait comparable ou devez-vous recourir à la lecture du javadoc? Si c’est le dernier cas, il est probable que chaque cas d’utilisation de tri futur nécessiterait un comparateur, auquel cas la mise en œuvre de comparable pourrait ralentir les utilisateurs de la classe, et non les accélérer.

75
Yishai

Utilisez Comparable si vous souhaitez définir un comportement d’ordre par défaut (naturel) de l’objet en question, une pratique courante consiste à utiliser un identifiant technique ou naturel (base de données?) De cet objet. .

Utilisez Comparator si vous souhaitez définir un comportement de commande contrôlable externe, vous pouvez remplacer le comportement de commande par défaut.

120
BalusC

Utilisez Comparable:

  • si l'objet est sous votre contrôle.
  • si le comportement de comparaison est le comportement de comparaison principal.

Utilisez Comparator:

  • si l'objet est en dehors de votre contrôle et que vous ne pouvez pas le faire implémenter Comparable.
  • lorsque vous voulez comparer un comportement différent du comportement par défaut (spécifié par Comparable).
52
Bozho

Comparable - Java.lang.Comparable: int compareTo(Object o1)

Un objet comparable est capable de se comparer à un autre objet. La classe elle-même doit implémenter l'interface Java.lang.Comparable pour pouvoir comparer ses instances.

  • Capable de comparer l'objet actuel avec l'objet fourni.
  • En utilisant cela, nous pouvons implémenter only one sort sequence en fonction des propriétés d'instance . EX: Person.id
  • Certaines des classes prédéfinies telles que String, Wrapper Class, Date, Calendar ont implémenté une interface comparable.

Comparateur - Java.util.Comparator: int compare(Object o1, Object o2)

Un objet comparateur est capable de comparer deux objets différents. La classe ne compare pas ses instances, mais certaines instances de la classe. Cette classe de comparaison doit implémenter l'interface Java.util.Comparator.

  • Capable de comparer deux objets du même type.
  • En utilisant ceci, nous pouvons implémenter many sort sequence et nommer chacun, en fonction des propriétés d'instance . EX: Person.id, Person.name, Person.age
  • Nous pouvons implémenter l'interface Comparator dans nos classes prédéfinies pour un tri personnalisé.

Exemple:

public class Employee implements Comparable<Employee> {

    private int id;
    private String name;
    private int age;
    private long salary;

    // Many sort sequences can be created with different names.
    public static Comparator<Employee> NameComparator = new Comparator<Employee>() {         
        @Override
        public int compare(Employee e1, Employee e2) {
            return e1.getName().compareTo(e2.getName());
        }
    };
    public static Comparator<Employee> idComparator = new Comparator<Employee>() {       
        @Override
        public int compare(Employee e1, Employee e2) {
            return Integer.valueOf(e1.getId()).compareTo(Integer.valueOf(e2.getId()));
        }
    };

    public Employee() { }
    public Employee(int id, String name, int age, long salary){
        this.id = id;
        this.name = name;
        this.age = age;
        this.salary = salary;
    }
    // setters and getters.

    // Only one sort sequence can be created with in the class.
    @Override
    public int compareTo(Employee e) {
    //return Integer.valueOf(this.id).compareTo(Integer.valueOf(e.id));
    //return Character.toString(this.name.charAt(0)).compareToIgnoreCase(Character.toString(e.name.charAt(0)));
        if (this.id > e.id) {
            return 1;
        }else if(this.id < e.id){
            return -1;
        }else {
            return Character.toString(this.name.charAt(0)).compareToIgnoreCase(Character.toString(e.name.charAt(0)));
        }

    }   

    public static void main(String[] args) {

        Employee e1 = new Employee(5, "Yash", 22, 1000);
        Employee e2 = new Employee(8, "Tharun", 24, 25000);

        List<Employee> list = new ArrayList<Employee>();
        list.add(e1);
        list.add(e2);
        Collections.sort(list); // call @compareTo(o1)
        Collections.sort(list, Employee.nameComparator); // call @compare (o1,o2)
        Collections.sort(list, Employee.idComparator); // call @compare (o1,o2)
    }
}
  • Pour le tri personnalisé, nous utilisons le comparateur @compare (o1, o2). Pour les autres scénarios, le modèle comparable @compareTo (o1), sans changer de code si nous voulons trier plus d'un champ, puis nous utilisons le comparateur. 

Pour Java 8 Lambda: Comparator reportez-vous à mon post.

19
Yash

Comparator fait tout ce qui est comparable, plus encore.

| | Comparable | Comparator ._______________________________________________________________________________ Is used to allow Collections.sort to work | yes | yes Can compare multiple fields | yes | yes Lives inside the class you’re comparing and serves | | as a “default” way to compare | yes | yes Can live outside the class you’re comparing | no | yes Can have multiple instances with different method names | no | yes Input arguments can be a list of | just Object| Any type Can use enums | no | yes

J'ai trouvé la meilleure approche pour utiliser les comparateurs en tant que classes anonymes comme suit:

private static void sortAccountsByPriority(List<AccountRecord> accounts) {
    Collections.sort(accounts, new Comparator<AccountRecord>() {

        @Override
        public int compare(AccountRecord a1, AccountRecord a2) {
            return a1.getRank().compareTo(a2.getRank());
        }
    });
}

Vous pouvez créer plusieurs versions de ces méthodes directement dans la classe que vous prévoyez de trier. Pour que vous puissiez avoir:

  • sortComptesPar Priorité 
  • sortAccountsByType
  • sortAccountsByPriorityAndType 

    etc...

Désormais, vous pouvez utiliser ces méthodes de tri n’importe où et obtenir une réutilisation du code ... Cela me donne tout ce que les comparables pourraient faire, plus encore ... donc je ne vois aucune raison de les utiliser.

9
user2773898

Comparable doit être utilisé lorsque vous comparez des instances de la même classe.

Le comparateur peut être utilisé pour comparer des instances de différentes classes.

Comparable est implémenté par la classe qui doit définir un ordre naturel pour ses objets . Comme String implémente Comparable.

Si l'on souhaite un ordre de tri différent, il peut mettre en œuvre un comparateur et définir sa propre façon de comparer deux instances.

9
Devang Paliwal

Je dirais:

  • si la comparaison est intuitive, alors certainement mettre en œuvre Comparable
  • si vous ne savez pas si votre comparaison est intuitive, utilisez un comparateur car il est plus explicite et donc plus clair pour la pauvre âme qui doit gérer le code
  • s'il y a plus d'une comparaison intuitive possible, je préférerais un comparateur, éventuellement construit par une méthode d'usine dans la classe à comparer.
  • si la comparaison a un but spécial, utilisez Comparateur
8
extraneon
  • Si, au moment de l’écriture de la classe, vous n’avez qu’un seul cas d'utilisation, le tri. Utilisez Comparable. 
  • Lorsque vous avez plus d’une stratégie de tri , Implémentez un comparateur
4
fabrizioM

Les points suivants vous aident à décider dans quelles situations utiliser Comparable et dans lequel Comparator:

1) Disponibilité du code

2) Critères de tri simples ou multiples

3) Arays.sort () et Collection.sort ()

4) Comme clés dans SortedMap et SortedSet

5) Plus de classes par rapport à la flexibilité

6) Comparaisons entre classes

7) ordre naturel

Pour un article plus détaillé, vous pouvez vous référer Quand utiliser comparable et quand utiliser comparateur

4
a Learner

Si vous avez besoin d'un tri d'ordre naturel - Comparable par l'utilisateur SI vous avez besoin d'un tri par ordre personnalisé - Utilisez le comparateur

Exemple:

Class Employee{
private int id;
private String name;
private String department;
}

Le tri par ordre naturel serait basé sur id car il serait unique et le tri par ordre personnalisé serait le nom et le département.

Références:
Quand une classe devrait-elle être comparable et/ou comparable?http://javarevisited.blogspot.com/2011/06/comparator-and-comparable-in-Java.html

3
Rajiv

Une question similaire se posait ici: Quand une classe devrait-elle être comparable et/ou comparable?

Je dirais ce qui suit: Implémenter Comparable pour quelque chose comme un ordre naturel, par exemple. basé sur un identifiant interne

Implémentez un comparateur si vous avez un algorithme de comparaison plus complexe, par ex. plusieurs champs et ainsi de suite.

3
ZeissS

Comparable:
Chaque fois que nous voulons stocker uniquement des éléments homogènes et l'ordre de tri naturel par défaut requis, nous pouvons opter pour la classe implémentant l'interface comparable.

Comparateur:
Lorsque nous voulons stocker des éléments homogènes et hétérogènes et que nous voulons trier dans l'ordre de tri personnalisé par défaut, nous pouvons opter pour l'interface comparator.

2
G swamy reddy

Si le tri des objets doit être basé sur l'ordre naturel, utilisez Comparable alors que si vous devez trier sur les attributs de différents objets, utilisez Comparator en Java.

Principale différence entre Comparable et Comparator:

+------------------------------------------------------------------------------------+
¦               Comparable                ¦                Comparator                ¦
¦-----------------------------------------+------------------------------------------¦
¦ Java.lang.Comparable                    ¦ Java.util.Comparator                     ¦
¦-----------------------------------------+------------------------------------------¦
¦ int objOne.compareTo(objTwo)            ¦ int compareTo(objOne, objTwo)            ¦
¦-----------------------------------------+------------------------------------------¦
¦ Negative, if objOne < objTwo            ¦ Same as Comparable                       ¦
¦ Zero,  if objOne == objTwo              ¦                                          ¦
¦ Positive,  if objOne > objTwo           ¦                                          ¦
¦-----------------------------------------+------------------------------------------¦
¦ You must modify the clas whose          ¦ You build a class separate from to sort. ¦
¦ instances you want to sort.             ¦ the class whose instances you want       ¦
¦-----------------------------------------+------------------------------------------¦
¦ Only one sort sequemce can be created   ¦ Many sort sequences can be created       ¦
¦-----------------------------------------+------------------------------------------¦
¦ Implemented frequently in the API by:   ¦ Meant to be implemented to sort          ¦
¦ String, Wrapper classes, Date, Calandar ¦ instances of third-party classes.        ¦
+------------------------------------------------------------------------------------+
2

Mon besoin était en quelque sorte basé sur la date.

Donc, j'ai utilisé Comparable et cela a fonctionné facilement pour moi.

public int compareTo(GoogleCalendarBean o) {
    // TODO Auto-generated method stub
    return eventdate.compareTo(o.getEventdate());
}

Une restriction avec Comparable est qu'ils ne peuvent pas être utilisés pour des collections autres que List.

0
spring pro

Comparable est l'ordre de tri naturel par défaut, à condition que les valeurs numériques soient ascendantes et les chaînes alphabétiques .. .., par exemple:

Treeset t=new Treeset();
t.add(2);
t.add(1);
System.out.println(t);//[1,2]

Le comparateur est l'ordre de tri personnalisé implémenté dans la classe personnalisée myComparator en surchargeant une méthode de comparaison .__, par exemple:

Treeset t=new Treeset(new myComparator());
t.add(55);
t.add(56);
class myComparator implements Comparator{
public int compare(Object o1,Object o2){
//Descending Logic
}
}
System.out.println(t);//[56,55]
0
Ajay Takur

Si vous possédez la classe, mieux vaut utiliser Comparable. Généralement, Comparator est utilisé si vous ne possédez pas la classe mais que vous devez l'utiliser TreeSet ou TreeMap car Comparator peut être passé en tant que paramètre dans le constructeur de TreeSet ou TreeMap. Vous pouvez voir comment utiliser Comparator and Comparable dans http://preciselyconcise.com/Java/collections/g_comparator.php

0
Sai Sunder

On m'a demandé de trier une gamme définie de nombres plus rapidement que jamais dans une interview. (Ne pas utiliser le tri par comptage)

L'implémentation d'une interface comparable sur un objet permet aux algorithmes de tri implicites d'utiliser la méthode compareTo remplacée pour ordonner les éléments de tri, ce qui correspond au temps linéaire.

0
Mr. Wonderful