Objekte vergleichen mit Comparable und Comparator

Bei den meisten primitiven Datentypen ist die natürliche Ordnung vorgegeben, sprich ob ein Wert größer, kleiner oder gleich groß is wie ein anderer Wert. Bei Objekten ist das ein wenig komplizierter.

Möchte man nun eine Liste mit Elementen der Klasse Person mit Vor- und Nachnamen sortieren, so ist nicht unbedingt klar wie sortiert werden soll. Kommt ein Alf Meier vor Rudi Huber oder umgekehrt?

Inhaltsverzeichnis

Das Interface Comparable

Um selbst zu bestimmen ob eine Instanz größer oder kleiner als ein anderes Objekt ist, kann eine Klasse das Interface Comparable implementieren. Comparable enthält nur die Methode compareTo(). Diese nimmt ein Objekt des selben Typs entgegen und gibt einem int-Wert zurück. Der Rückgabewert bestimmt wie der Vergleich ausfällt:

  • Das Objekt ist kleiner als das übergebene Objekt: Negativer int-Wert, z.B. -1
  • Das Objekt ist gleich groß wie das übergebene Objekt: Null als Zahl: 0
  • Das Objekt ist größer als das übergebene Objekt: Positiver int-Wert, z.B. 1

Möchte man Personen nach dem Nachnamen ordnen, kann man das Interface Comparable bzw. die Methode compareTo() wie folgt implementieren:

public class Person implements Comparable{
    private String firstName;
    private String lastName;

    public Person(String firstName, String lastName){
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    @Override
    public String toString() {
        return "Person{firstName='" + firstName + "', lastName='" + lastName + "'}";
    }

    @Override
    public int compareTo(Object o) {
        Person other = (Person) o;
        return this.lastName.compareTo(other.lastName);
    }
}

Eine Liste von Personen kann nun wie folgt sortiert werden:

List<Person> persons = Arrays.asList(
        new Person("Tom", "Jones"),
        new Person("James", "Brown"),
        new Person("Carlos", "Santana"));

Collections.sort(persons);
System.out.println(persons);
// Ausgabe: [Person{firstName='James', lastName='Brown'}, Person{firstName='Tom', lastName='Jones'}, Person{firstName='Carlos', lastName='Santana'}]

Achtung! Diese Variante ist nicht Null-sicher (null-safe). Wenn ein Nachname nun null sein sollte wirft die compareTo() Methode eine NullPointerException!

↑ Nach oben

Das Interface Comparator (Comparator-Objekt)

Der Vergleich mit der Methode compareTo() im InterfaceComparable im obigen Beispiel hat ein Problem: wie verglichen wird ist fix festgelegt. Möchte man nun nicht aufsteigend, sondern absteigend oder nach dem Vornamen sortieren funktioniert das nicht.

Für diese Fälle gibt es das Interface Comparator. Es enhält ebenfalls eine compareTo() Methode, diese nimmt allerdings zwei Argumente des selben Typs entgegen. Der Rückgabewert ist wie im obigen Fall ein negativer Integer wenn das erste Objekt kleiner ist als das zweite, ein positiver Wert wenn das erste Objekt größer ist als das zweite oder die Zahl Null wenn beide Objekte gleich groß sind.

Nun gibt es verschiedene Arten wie das Interface angewendet werden kann:

Comparator Klasse

Die zweite Möglichkeit ist, für jede Art zu sortieren eine eigene Klasse zu erstellen. Der Nachteil ist, dass im Endeffekt viele Klassen erstellt werden müssen um alle Möglichkeiten abzudecken. Der Vorteil ist, dass nicht jedes mal eine anonyme Klasse erstellt werden muss, was in doppeltem Code resultiert.

public class FirstNameComparator implements Comparator<Person>{

    @Override
    public int compare(Person first, Person second) {
        return first.getFirstName().compareTo(second.getFirstName());
    }
}

Die Klasse FirstNameComparator sortiert die Personen in einer Liste nun nach dem Vornamen:

List<Person> persons = Arrays.asList(
        new Person("Tom", "Jones"),
        new Person("James", "Brown"),
        new Person("Carlos", "Santana"));

Collections.sort(persons, new FirstNameComparator());
System.out.println(persons);
// Ausgabe: [Person{firstName='Carlos', lastName='Santana'}, Person{firstName='James', lastName='Brown'}, Person{firstName='Tom', lastName='Jones'}]

Anonyme Klasse

Um nicht immer eine neue Klasse in einem neuen Java-File erstellen zu müssen, kann ein Komparator-Objekt auch in einer anonymen Klasse erstellt werden:

Collections.sort(persons, new Comparator<Person>() {
    @Override
    public int compare(Person first, Person second) {
        return first.getFirstName().compareTo(second.getFirstName());
    }
});

Dieser Code resultiert im selben Ergebnis wie der obige Code, ist aber quasi ein Einzeiler.

Achtung! Diese Varianten sind nicht Null-sicher (null-safe). Wenn der Vorname von einem der Argumente null ist, wirft die compareTo() Methode eine NullPointerException!

↑ Nach oben


Ähnliche Artikel