Java Comparator schreiben?
Ich hab folgende Aufgabe, ich soll Spielkarten in Java sortieren.
Mein Prof schrieb folgendes in die Aufgabe:
Mit erster Priorität nach Rängen (Rank) und zwar Ass vor König, König vor Dame, Dame vor Bube, Bube vor 10, 10 vor 9, 9 vor 8, 8 vor 7, 7 vor 6, 6 vor 5, 5 vor 4, 4 vor 3 und 3 vor 2.
und
Mit zweiter Priorität nach Farben (Suit) und zwar Kreuz vor Pik, Pik vor Herz, Herz vor Karo.
Meine jetzige implementation sieht so aus:
@Override
public int compare(Card o1, Card o2) {
if (o1.equals(o2))
return 0;
int comparedValue = Integer.compare(o1.getRank().ordinal(), o2.getRank().ordinal());
if (comparedValue != 0)
return comparedValue;
comparedValue = Integer.compare(o1.getSuit().ordinal(), o2.getRank().ordinal());
return comparedValue;
}
Nur hab ich da Bauchschmerzen. Erstens, wie geht man dort mit null um? Oder ist das egal?
Dann ist das mit der Ordnung so richtig? Also dass ich gucke, ob der Rank einen unterschied hat, wenn ja, dann return, wenn nicht, soll er die Farbe nehmen.
Technisch funktioniert der Code, mir geht's eher darum, obs semantisch korrekt ist und zur Aufgabe passt.
Dann halt wie man den Nullpointer verhindert. Also ob man eine Exception (in meinem fall Assert false, weil Exception noch verboten), oder ob man 0 oder Integer.max/min nimmt.
Dann noch ne frage am rand. Der obige Code sortiert falsch herum. Wie macht man das jetzt am besten. Ich hab einfach *=-1; gemacht, oder tauscht man die objekte als parameter? Oder wie macht man das elegant?
2 Antworten
Am Anfang würde ich überprüfen, ob o1 und o2 null sind und würde dann einen sinnigen Wert zurück geben. Beim Compare würde ich o1 und o2 vertauschen, dann sortiert er vermutlich richtig. Eine try...catch Klammer wäre auch nicht schlecht
Erstens, wie geht man dort mit null um? Oder ist das egal?
Das ist nicht egal; du kannst dich entscheiden was das gewünschte Verhalten ist. Die Spezifikation von Comparator<T>.compare() erlaubt dir das: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Comparator.html#compare(T,T)
In vielen Fällen ist es durchaus sinnvoll, eine NullPointerException zu werfen statt stillschweigend irgendein Ersatzverhalten zu implementieren, das zu überraschenden Ergebnissen führt. Mit Objects.requireNonNull() geht das kurz.
Der obige Code sortiert falsch herum. Wie macht man das jetzt am besten.
Ich verstehe nicht ganz. Wenn compare() das falsche Vorzeichen liefert, dann dreh halt drin die Vorzeichen oder die Reihenfolge um.
Rank und Suit scheinen doch enums zu sein, und die sind schon selbst Comparable. D.h. es sollte reichen, sie direkt mit compareTo() zu vergleichen, statt selber mit getOrdinal() herumzufuhrwerken. Damit wird der Code schon mal kürzer und lesbarer.
Am Schluss kannst du dir die Zuweisung zu comparedValue sparen.
Wenn ich sowas selber implementieren müsste, würde ich vermutlich zu Comparator.comparing() greifen. Aber das dürft ihr dann wohl nicht.
Wenn ich object.requireNonNull verwende schlägt mich mein prof vermutlich noch, da wir nur das verwenden dürfen, was wir gelernt haben 😂
Das würde assert false bedeuten in meinem Fall ._.
Das mit dem Vorzeichen hab ich gemeint mit *-1 :) scheint wohl dann das beste zu sein
Würdest du den Code noch anders schreiben (also bis auf die null checks?)