Wie stelle ich mithilfe compareTo() die natürliche Objektreihenfolge her (Java)?

3 Antworten

Vom Fragesteller als hilfreich ausgezeichnet

Noch ein paar zusätzliche Gedanken:

Studenten haben keine natürliche Ordnung. Wenn man dir z.B. 10 Studenten hinstellt und sagt "sortier die mal", dann ist nicht automatisch klar, nach welchem Kriterium sie sortiert werden (es könnte z.B. nach Name (erst Nachname, dann Vorname oder vielleicht auch andersrum), nach Alter, nach Punktzahl, nach Größe, nach Farbe des Pullovers etc. sein). Von daher ist es untypisch, eine Klasse "Student" das Interface Comparable<Student> implementieren zu lassen.

In der Java-Dokumentation steht auch, dass dringend empfohlen wird, dass die compareTo-Funktion konsistent zu der equals-Funktion ist. Also anders gesagt: Wenn die compareTo-Funktion zurückgibt, dass zwei Objekte gleich sind (Rückgabewert 0), dass dann auch die equals-Funktion zurückgeben sollte, dass zwei Objekte gleich sind. Das ist aber nicht der Fall, wenn du zwei Studenten mit der gleichen Punktzahl hast.

Normalerweise würdest du also der Sortierfunktion direkt ein Kriterium mitgeben, nach dem sortiert werden soll. Z.B absteigend nach Punktzahl:

studentenListe.sort(Comparator.comparing(Student::getPunktzahl).reversed());

Nur falls es jetzt für besondere Anlässe eine bestimmte Sortierung gibt (z.B. bei der Zeugnisaugabe am Ende des Studiums sollen alle zuerst absteigend nach Punktzahl, dann nach Nachname und dann nach Vorname sortiert sein), könntest du einen Comparator als öffentliche Konstante in deine Klasse aufnehmen:

public static final Comparator<Student> COMP_ZEUGNISAUSGABE = Comparator.comparing(Student::getPunktzahl).reversed().thenComparing(Student::getNachname).thenComparing(Student::getVorname);

Und noch ein Tipp:

Mal angenommen, Studenten hätten eine natürliche Sortierung nach Punktzahl, würde ich dir empfehlen, die vorhandene compare-Funktion für den jeweiligen Variablentyp zu nehmen. Dadurch vermeidest du Flüchtigkeitsfehler. Z.B. bei int-Werten:

@Override
public int compareTo(Student other) {
	return Integer.compare(this.punktzahl, other.punktzahl);
}
KathaHohenfels 
Fragesteller
 11.04.2022, 21:13
Von daher ist es untypisch, eine Klasse "Student" das Interface Comparable<Student> implementieren zu lassen.

Die Aufgabenstellung war halt entsprechend.

In der Java-Dokumentation steht auch, dass dringend empfohlen wird, dass die compareTo-Funktion konsistent zu der equals-Funktion ist. Also anders gesagt: Wenn die compareTo-Funktion zurückgibt, dass zwei Objekte gleich sind (Rückgabewert 0), dass dann auch die equals-Funktion zurückgeben sollte, dass zwei Objekte gleich sind. Das ist aber nicht der Fall, wenn du zwei Studenten mit der gleichen Punktzahl hast.

Wie ändere ich das dann, sodass compareTo() konsistent zu equals() ist? ist das überhaupt möglich? bedeutet das nicht, dass zwei Studenten nicht die gleiche Punktzahl haben dürfen, denn wenn, dann müsste es der gleiche Student sein?

Dadurch vermeidest du Flüchtigkeitsfehler. Z.B. bei int-Werten

Was für Flüchtigkeitsfehler vermeide ich damit?

lg Kath

0
daCypher  12.04.2022, 10:23
@KathaHohenfels
Die Aufgabenstellung war halt entsprechend.

Ja, mir ist leider schon öfter aufgefallen, dass Lehrer versuchen, sich irgendwelche Aufgaben auszudenken, die dann völlig absurd sind und die man als Programmierer niemals so bauen würde. In dem Fall kannst du natürlich einfach die Variante nehmen, die ich als letztes in meiner Antwort geschrieben habe.

Wie ändere ich das dann, sodass compareTo() konsistent zu equals() ist?

Im Falle der Studenten geht es gar nicht (bzw. nur mit der Einschränkung, dass zwei Studenten als Gleich angesehen werden, wenn sie die gleiche Punktzahl haben. Wenn du jetzt versuchen würdest, ein HashSet mit Studenten zu füllen, könntest du aber keine zwei Studenten mit gleicher Punktzahl einfügen.)

Bei Klassen, die tatsächlich eine natürliche Ordnung haben (z.B. Zahlen) kannst du einfach die Methode "equals(Object other)" überschreiben, damit sie True zurückgibt, wenn beide Objekte den gleichen Wert haben. Wenn du es einfach haben willst, kannst du da auch einfach prüfen, ob compareTo() eine 0 zurückgibt.

Was für Flüchtigkeitsfehler vermeide ich damit?

In erster Linie, dass du die Objekte oder die Operatoren nicht vertauschst, also versehentlich die Sortierung umkehrst, oder wie in deinem Fall dass du nur zwei von drei Möglichkeiten abdeckst. Davon abgesehen braucht es auch weniger Hirnschmalz, wenn du einfach die Funktionen benutzt, bei denen sich schon jemand anderes Gedanken drum gemacht hat.

Ich finde z.B. das hier:

return Integer.compare(this.punktzahl, other.punktzahl);

einfacher und übersichtlicher, als das hier:

if (this.punktzahl < other.punktzahl) {
	return -1;
} else if (this.punktzahl > other.punktzahl) {
	return 1;
} else {
	return 0;
}

Eine Alternative wäre auch noch:

return (int) Math.signum(this.punktzahl - other.punktzahl);

oder

return Integer.valueOf(this.punktzahl).compareTo(other.punktzahl);
1

Nein die compareto soll das gar nicht mache. Und niemand der sie benutzt würde erwarten daß sie irgendwas ordnet. Das geht auch gar nicht.

Du hast die Dokumentation falsch gelesen. Da steht wenn die Objekte eine Reihenfolge haben. Dann kann. Man diese Methode überschreiben.

Orden muss man die Elemente in einer Liste etc. Schon selbst. Oder man verwendet listen etc. Die sich automatisch ordnen die rufen dann ggf implizit die compareto auf.

Bei Studenten könnte man sich eine natürliche Ordnung z.b. nach Namen vorstellen etc.

Das Icomoarwable Interface sagt dem Benutzer im Grunde nur das man diese Objekte einfach ordnen kann. Ohne sich jetzt selbst Gedanken zu machen nach was man diese ordnen möchte.

Woher ich das weiß:Studium / Ausbildung – Bachelor
KathaHohenfels 
Fragesteller
 10.04.2022, 16:28

Aaaah okay dankeschön! Also man nutzt das dann quasi wenn man weiß, wie die Objekte sortiert sein sollen, um die Sortierung zu prüfen und wenn man weiß wie sie sortiert sein sollten, aber auch weiß, dass sie noch nicht so sortiert sind, um sie entsprechend mithilfe der Methode dann sortiert einzuordnen?

0
FouLou  10.04.2022, 16:30
@KathaHohenfels

Sie macht Objekte schlichtweg vergleichbar. Ohne das man sich als derjenige der die Objekte benutzt darum kümmern muss.

Als Beispiel sind zahlen ja per se vergleichbar.

Studenten. Oder Autos oder andere Objekte sind es aber nicht von Haus aus. Und genau dafür ist diese Methode gedacht.

0
KathaHohenfels 
Fragesteller
 10.04.2022, 16:28

Was meinst du mit "Icomoarwable Interface"?

0
FouLou  10.04.2022, 16:32
@KathaHohenfels

Doffe Schreibfehler.

Nur das: Comparable<T>

Interfaces werden üblicherweise mit einem I am Anfang angegeben. Ist aber nicht in jeder Sprache so.

1
FouLou  10.04.2022, 16:35
@KathaHohenfels

Oh. Und deine Überschreibung ist glaube ich nicht ganz korrekt. Compareto gibt 3 mögliche Werte zurück. Bzw würde man das erwarten.

-1 das Element was übergeben würde ist kleiner

0 die Elemente sind gleich.

1 das Element was übergeben wurde ist größer.

Du gibst glaube ich nur 1 und 0 zurück wie ich sehe.

1
KathaHohenfels 
Fragesteller
 10.04.2022, 17:14
@FouLou

Ja, weil ich das so wollte, dass wenn es kleiner oder gleich groß ist, das gleiche passiert (also wenn es größer ist vorne anfügen, wenn kleiner oder gleich groß hinter dem, womit es verglichen wird. Dadurch ist quasi bei gleichen Werten das vorher Eingefügte vor dem, was danach eingefügt wurde in der Reihenfolge).

0
FouLou  10.04.2022, 18:38
@KathaHohenfels

Keine gute Idee nach meiner Ansicht. 0 bedeutet gleich. Wenn ich Student A mit 12 Punkte habe. Und Student B mit 9 und dann B mit A vergleiche. Bekomme ich das Ergebniss gleich. Wenn ich aber A mit B vergleiche dann das Ergebnis A ist grosser als A.

Wenn du nur wissen willst ob this größer als der Parameter ist dann ist es sinnvoller ne greaterthan Methode zu implementieren.

Wenn du aber Methoden so implementierst das sie Inkonsistente Werte zurück gibt (wie im Beispiel einen unerwarteten Unterschied ob man nun a und B Vergleich und B und A.

Dann wird dich das früher oder später in den Hintern beißen. Weil dann eventuell ganz unerwartet ein program komisches verhalten zeigt und der Fehler Sau schwer zu finden sein wird. Z.b. wenn man B und A als gleich behandelt obwohl B kleiner ist als A. (Compare muss -1 zurückgeben)

1
FouLou  10.04.2022, 18:41
@FouLou

Als Beispiel könnte die Sort() Methode vom Array die die compare nutzt manche Arrays korrekt sortieren. Aber bei manch anderen eventuell Fehler machen und diese nicht mehr korrekt sortieren.

1

Normalerweise gibts noch die methode sort und der übergibt man die methode compareto damit das richtige this.points verglichen werden können bei jedem objekt was übergeben wurde . sprich das ist die sortierfunktion für sort() ;

KathaHohenfels 
Fragesteller
 10.04.2022, 17:14

und woher ist die Methode sort() dann? also woher kommt die?

0