Vorsicht im Umgang mit SortedSet

Sortierte Mengen werden häufig als Implementierungen des Interfaces SortedSet umgesetzt. Dieses Interface sieht vor, dass die Elemente einer solchen Menge entweder gemäß ihrer natürlichen Ordnung (durch die compareTo-Methode von Comparable definiert) oder durch einen Comparator sortiert werden. Manch einer übersieht dabei aber eine wichtige Voraussetzung an die compareTo- bzw. compare-Methode: Sie muß mit der equals-Methode konsistent sein, d.h. für zwei Objekte a und b muß a.equals(b) genau dann true zurückliefern, wenn a.compareTo(b) (bzw. die compare-Methode des Comparators) den Wert 0 liefert. Wenn dies nicht der Fall ist, verhält sich die Collection möglicherweise nicht mehr wie eine Menge, d.h. es ist nicht mehr sichergestellt, dass

  1. es keine zwei (im Sinne von equals) gleichen Elemente in der Menge gibt.
  2. man ein Element, das sich (im Sinne von equals) von allen Elemten innerhalb der Collection unterscheidet, einfügen kann.

In diesem Fall wäre man mit einem gewöhnlichen Set, das man selbst mit Hilfe von Collections.sort() sortiert, besser beraten. Ein kleines Beispiel soll das Problem verdeutlichen:
Die Klasse Person überschreibt equals derart, dass Personen mit gleicher id als gleich betrachtet werden:

public class Person {
  private Integer id;
  private Integer age;
  public Integer getId() {
      return id;
  }
  public void setId(final Integer id) {
      this.id = id;
  }
  public Integer getAge() {
      return age;
  }
  public void setAge(final Integer age) {
    this.age = age;
  }
 
  @Override
  public boolean equals(final Object obj) {
    if (obj instanceof Person && id==(((Person)obj).id))
      return true;
    else
      return false;
  }
 
  public Person(final Integer id, final Integer age) {
    this.id = id;
    this.age = age;
  }
}

Wir definieren nun einen Comparator, der Personen nach ihrem Alter vergleicht und legen mit dessen Hilfe ein SortedSet an, in das wir zwei verschiedene Personen einfügen:

import java.util.Comparator;
import java.util.SortedSet;
import java.util.TreeSet;
 
public class Example {
 
  public static void main(final String[] args) {
    Comparator comp = new Comparator() {
      @Override
      public int compare( Person o1, Person o2) {
        return o1.getAge().compareTo(o2.getAge());
      }
    };
    SortedSet exampleSet =
      new TreeSet(comp);
    exampleSet.add(new Person(1,25));
    exampleSet.add(new Person(2,25));
    System.out.println("Size: "+exampleSet.size());
  }
}

Die Ausgabe bestätigt: es wurde lediglich eine Person tatsächlich in die Menge aufgenommen, obwohl die Personen anhand der equals-Methode eindeutig unterschieden werden. Bei komplexeren Comparator-Klassen kann es durchaus sinnvoll sein, die Konsistenz von equals-Methode und Comparator mittels eines eigenen Tests sicherzustellen. Aber bereits ein sorgfältiger Blick zur rechten Zeit kann einen hier vor schwer auffindbaren Fehlern bewahren.


Malte Wulf

Tags: ,

  • Share/Bookmark

Eine Antwort zu “Vorsicht im Umgang mit SortedSet”

  1. [...] zwischen der compareTo() und der equals() Methode bei der Verwendung des SortedSet Interfaces. [Link] Lesezeichen erstellen  Artikel per E-Mail empfehlen Links Tags: App [...]

Hinterlasse eine Antwort