Verwendung von Comparable und Comparator


108

Ich habe eine Liste von Objekten, die ich auf einem Feld sortieren muss, z. B. Punktzahl. Ohne viel nachzudenken habe ich eine neue Klasse geschrieben, die Comparator implementiert, die die Aufgabe erledigt und funktioniert.

Wenn ich jetzt zurückblicke, frage ich mich, ob ich stattdessen meine Klasse Comparable implementieren lassen sollte, anstatt eine neue Klasse zu erstellen, die Comparator implementiert. Die Punktzahl ist das einzige Feld, in dem die Objekte bestellt werden.

  1. Was habe ich als Praxis akzeptabel gemacht?

  2. Ist der richtige Ansatz "Lassen Sie zuerst die Klasse Comparable implementieren (für die natürliche Reihenfolge) und wenn ein alternativer Feldvergleich erforderlich ist, erstellen Sie eine neue Klasse, die Comparator implementiert"?

  3. Wenn (2) oben wahr ist, bedeutet dies, dass man Comparator erst implementieren sollte, nachdem die Klasse Comparable implementiert hat? (Vorausgesetzt, ich besitze die ursprüngliche Klasse).

Antworten:


80

Ich würde sagen, dass ein Objekt Comparable implementieren sollte, wenn dies die klare natürliche Art ist, die Klasse zu sortieren, und jeder, der die Klasse sortieren müsste, dies im Allgemeinen so tun möchte.

Wenn die Sortierung jedoch eine ungewöhnliche Verwendung der Klasse war oder die Sortierung nur für einen bestimmten Anwendungsfall sinnvoll ist, ist ein Komparator eine bessere Option.

Anders ausgedrückt: Ist es angesichts des Klassennamens klar, wie ein vergleichbarer Typ sortieren würde, oder müssen Sie auf das Lesen des Javadoc zurückgreifen? Wenn es das letztere ist, besteht die Wahrscheinlichkeit, dass jeder zukünftige Anwendungsfall für die Sortierung einen Komparator erfordert. Zu diesem Zeitpunkt kann die Implementierung von vergleichbar Benutzer der Klasse verlangsamen und nicht beschleunigen.


Können Sie bitte ein kurzes Beispiel geben?
Kammer

Dies könnte ein gutes Beispiel sein: gist.github.com/yclian/2627608 Es gibt eine Versionsklasse, die ComparableVersion verwendet. Version - bietet Factory-Methoden ComparableVersion soll Objekt sein (ohne statische Methoden) - bietet eine Version, die mit einer anderen verglichen werden kann. Verantwortlichkeiten sind getrennt.
ses


Der Interviewer fragte, warum er Comparator verwenden sollte, wenn dies auch mit
Comparable möglich ist

@ aLearner Link ist tot
G. Brown

127

Verwenden ComparableSie diese Option, wenn Sie ein standardmäßiges (natürliches) Ordnungsverhalten des betreffenden Objekts definieren möchten. In der Regel wird hierfür eine technische oder natürliche (Datenbank?) Kennung des Objekts verwendet.

Verwenden ComparatorSie diese Option, wenn Sie ein extern steuerbares Bestellverhalten definieren möchten. Dies kann das Standardbestellverhalten überschreiben.


3
Das ist eine technische Erklärung und so richtig wie sie kommt, aber sie sagt nichts über Best Practices aus.
extraneon

40
Es sagt, wann jeder verwendet werden soll - wenn dies keine bewährte Methode ist, was ist es dann?
Bozho

1
"Bedeutet das Implementieren Comparable, dass ich die natürliche Ordnung definiere?" Dies gab mir die Antwort, die ich suchte. Danke :)
Somjit

61

Verwendung Comparable:

  • wenn sich das Objekt in Ihrer Kontrolle befindet.
  • wenn das Vergleichsverhalten das Hauptvergleichsverhalten ist.

Verwendung Comparator:

  • Wenn sich das Objekt außerhalb Ihrer Kontrolle befindet und Sie es nicht implementieren können Comparable.
  • Wenn Sie ein Verhalten vergleichen möchten, das sich vom Standardverhalten (das durch angegeben wird Comparable) unterscheidet.

20

Vergleichbar -java.lang.Comparable: int compareTo(Object o1)

Ein vergleichbares Objekt kann sich mit einem anderen Objekt vergleichen. Die Klasse selbst muss die Schnittstelle java.lang.Comparable implementieren, um ihre Instanzen vergleichen zu können.

  • Kann das aktuelle Objekt mit dem bereitgestellten Objekt vergleichen.
  • Auf diese Weise können wir only one sort sequencebasierend auf den Instanzeigenschaften implementieren . EX:Person.id
  • Einige der vordefinierten Klassen wie String, Wrapper-Klassen, Datum und Kalender haben eine vergleichbare Schnittstelle implementiert.

Komparator -java.util.Comparator: int compare(Object o1, Object o2)

Ein Komparatorobjekt kann zwei verschiedene Objekte vergleichen. Die Klasse vergleicht nicht ihre Instanzen, sondern die Instanzen einiger anderer Klassen. Diese Komparatorklasse muss die Schnittstelle java.util.Comparator implementieren.

  • Kann zwei Objekte des gleichen Typs vergleichen.
  • Auf diese Weise können wir many sort sequencejede basierend auf den Instanzeigenschaften implementieren und benennen. EX:Person.id, Person.name, Person.age
  • Wir können die Comparator-Schnittstelle für unsere vordefinierten Klassen für die benutzerdefinierte Sortierung implementieren.

Beispiel:

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)
    }
}
  • Für die benutzerdefinierte Sortierung wählen wir den Komparator @compare (o1, o2) für andere Szenarien. Wir wählen den vergleichbaren @compareTo (o1). Ohne Code zu ändern, wenn wir mehr als ein Feld sortieren möchten, verwenden wir den Komparator.

Für Java 8 Lambda: Comparator siehe meinen Beitrag.


10

Vergleichbar sollte verwendet werden, wenn Sie Instanzen derselben Klasse vergleichen.

Mit dem Komparator können Instanzen verschiedener Klassen verglichen werden.

Comparable wird von Klassen implementiert, die eine natürliche Reihenfolge für ihre Objekte definieren müssen. Like String implementiert Comparable.

Wenn jemand eine andere Sortierreihenfolge wünscht, kann er einen Komparator implementieren und seine eigene Art des Vergleichs zweier Instanzen definieren.


10

Wenn das Sortieren von Objekten auf der natürlichen Reihenfolge basieren muss, verwenden Sie Comparable. Wenn das Sortieren nach Attributen verschiedener Objekte erfolgen muss, verwenden Sie Comparator in Java.

Hauptunterschiede zwischen Comparable und Comparator:

+------------------------------------------------------------------------------------+
¦               Comparable                ¦                Comparator                ¦
¦-----------------------------------------+------------------------------------------¦
¦ java.lang.Comparable                    ¦ java.util.Comparator                     ¦
¦-----------------------------------------+------------------------------------------¦
¦ int objOne.compareTo(objTwo)            ¦ int compare(objOne, objTwo)              ¦
¦-----------------------------------------+------------------------------------------¦
¦ Negative, if objOne < objTwo            ¦ Same as Comparable                       ¦
¦ Zero,  if objOne == objTwo              ¦                                          ¦
¦ Positive,  if objOne > objTwo           ¦                                          ¦
¦-----------------------------------------+------------------------------------------¦
¦ You must modify the class whose         ¦ You build a class separate from to sort. ¦
¦ instances you want to sort.             ¦ the class whose instances you want       ¦
¦-----------------------------------------+------------------------------------------¦
¦ Only one sort sequence 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, Calendar ¦ instances of third-party classes.        ¦
+------------------------------------------------------------------------------------+

9

Der Komparator macht alles, was der Vergleich macht, und noch mehr.

| | 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

Ich fand den besten Ansatz, Komparatoren als anonyme Klassen zu verwenden, wie folgt:

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());
        }
    });
}

Sie können mehrere Versionen solcher Methoden direkt in der Klasse erstellen, die Sie sortieren möchten. So können Sie haben:

  • sortAccountsByPriority
  • sortAccountsByType
  • sortAccountsByPriorityAndType

    etc...

Jetzt können Sie diese Sortiermethoden überall verwenden und Code wiederverwenden. Dies gibt mir alles, was vergleichbar wäre, und noch mehr ... also sehe ich keinen Grund, überhaupt vergleichbar zu verwenden.


8

Ich würde sagen:

  • Wenn der Vergleich intuitiv ist, implementieren Sie auf jeden Fall Comparable
  • Wenn unklar ist, ob Ihr Vergleich intuitiv ist, verwenden Sie einen Komparator, da dieser für die arme Seele, die den Code pflegen muss, expliziter und damit klarer ist
  • Wenn mehr als ein intuitiver Vergleich möglich ist, würde ich einen Komparator bevorzugen, der möglicherweise nach einer Factory-Methode in der zu vergleichenden Klasse erstellt wird.
  • Wenn der Vergleich speziell ist, verwenden Sie Comparator

6

Die folgenden Punkte helfen Ihnen bei der Entscheidung, in welchen Situationen Comparable und in welchem ​​Comparator verwendet werden soll:

1) Codeverfügbarkeit

2) Einzel- und Mehrfachsortierkriterien

3) Arays.sort () und Collection.sort ()

4) Als Schlüssel in SortedMap und SortedSet

5) Mehr Anzahl von Klassen versus Flexibilität

6) Klassenvergleiche

7) Natürliche Ordnung

Ausführlichere Artikel finden Sie unter Wann ein vergleichbarer und wann ein Komparator zu verwenden ist


Ich frage mich, warum niemand diese Antwort positiv bewertet. Es ist wirklich schön. +1
Diganta

4
  • Wenn Sie zum Zeitpunkt des Schreibens der Klasse nur einen Anwendungsfall für die Sortierung haben, verwenden Sie Comparable.
  • Nur wenn Sie mehr als eine Sortierstrategie haben, implementieren Sie einen Komparator.

4

Wenn Sie eine natürliche Auftragssortierung benötigen - Benutzervergleichbar WENN Sie eine benutzerdefinierte Auftragssortierung benötigen - Verwenden Sie den Komparator

Beispiel:

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

Die Sortierung nach natürlicher Reihenfolge würde auf der ID basieren, da sie eindeutig wäre und die Sortierung nach benutzerdefinierter Reihenfolge Name und Abteilung wäre.

Refrences:
Wann sollte eine Klasse vergleichbar und / oder vergleichend sein? http://javarevisited.blogspot.com/2011/06/comparator-and-comparable-in-java.html


3

Hier hatte es eine ähnliche Frage gegeben: Wann sollte eine Klasse vergleichbar und / oder vergleichend sein?

Ich würde folgendes sagen: Implementiere Comparable für so etwas wie eine natürliche Reihenfolge, zB basierend auf einer internen ID

Implementieren Sie einen Komparator, wenn Sie einen komplexeren Vergleichsalgorithmus haben, z. B. mehrere Felder usw.


1
Die Bestellung auf mehreren Feldern kann genauso gut erledigt werden Comparable.
BalusC

Für den Unterschied zwischen vergleichbar und Vergleich können Sie java-journal.blogspot.in/2010/12/…
ein Lernender

2

Vergleichbar:
Wann immer wir nur homogene Elemente speichern möchten und die standardmäßige natürliche Sortierreihenfolge erforderlich ist, können wir uns für eine Klasse-Implementierungsschnittstelle entscheiden comparable.

Komparator:
Wann immer wir homogene und heterogene Elemente speichern und in der benutzerdefinierten Standard-Sortierreihenfolge sortieren möchten, können wir uns für die comparatorSchnittstelle entscheiden.


0

Mein Bedarf war nach Datum sortiert.

Also habe ich Comparable verwendet und es hat für mich problemlos funktioniert.

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

Eine Einschränkung bei Comparable besteht darin, dass sie nicht für andere Sammlungen als List verwendet werden können.


0

Wenn Sie die Klasse besitzen, gehen Sie besser mit Comparable . Im Allgemeinen wird Comparator verwendet, wenn Sie die Klasse nicht besitzen, aber ein TreeSet oder TreeMap verwenden müssen, da Comparator als Parameter im Konstruktor von TreeSet oder TreeMap übergeben werden kann. Informationen zur Verwendung von Comparator und Comparable finden Sie unter http://preciselyconcise.com/java/collections/g_comparator.php


0

Ich wurde gebeten, in einem Interview einen bestimmten Zahlenbereich besser als nlogn zu sortieren. (Keine Zählsortierung)

Durch die Implementierung einer vergleichbaren Schnittstelle über ein Objekt können implizite Sortieralgen die überschriebene compareTo-Methode verwenden, um Sortierelemente zu ordnen. Dies wäre eine lineare Zeit.


0

Vergleichbar ist die standardmäßige natürliche Sortierreihenfolge, die für aufsteigende numerische Werte und für alphabetische Zeichenfolgen angegeben ist. für zB:

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

Comparator ist die benutzerdefinierte Sortierreihenfolge, die in der benutzerdefinierten myComparator-Klasse implementiert wird, indem eine Vergleichsmethode überschrieben wird, z.

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]

-1

Ein sehr einfacher Ansatz besteht darin, anzunehmen, dass die betreffende Entitätsklasse in der Datenbank und dann in der Datenbanktabelle dargestellt wird. Benötigen Sie einen Index, der aus Feldern der Entitätsklasse besteht? Wenn die Antwort Ja lautet, implementieren Sie vergleichbar und verwenden Sie die Indexfelder für die natürliche Sortierreihenfolge. In allen anderen Fällen verwenden Sie einen Komparator.


-2

Meine Annotation lib für die Implementierung Comparableund Comparator:

public class Person implements Comparable<Person> {         
    private String firstName;  
    private String lastName;         
    private int age;         
    private char gentle;         

    @Override         
    @CompaProperties({ @CompaProperty(property = "lastName"),              
        @CompaProperty(property = "age",  order = Order.DSC) })           
    public int compareTo(Person person) {                 
        return Compamatic.doComparasion(this, person);         
    }  
}

Klicken Sie auf den Link, um weitere Beispiele anzuzeigen. http://code.google.com/p/compamatic/wiki/CompamaticByExamples

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.