Mit genau dieser Fehlermeldung kam Bizarrus vor einigen Wochen verwundert auf mich zu und hat gefragt, warum seine App solche komischen Exceptions wirft.
Wir haben die Antwort gefunden und ich möchte euch kurz davon erzählen.
Die Fehlermeldung „Comparison method violates its general contract“ kommt aus der Java-Welt und bedeutet, dass bei einer Klasse, die das Interface Comparator implementiert der Vertrag nicht eingehalten wurde, dass Dinge beim Vergleich immer schlussfolgernd dieselbe Reihenfolge haben.
Das bedeutet: Wenn A kleiner B und B kleiner C, dann ist A kleiner als C.
Doch, warum wurde überhaupt ein Java-Comparator benutzt, wenn man nur Javascript mit User Apps programmieren kann?
Der Code, der die Probleme bereitet hat war Code, der ein Array um eine Shuffle-Funktion erweitern sollte. Bizarrus hatte ihn auf Stackoverflow gefunden:
if(!Array.prototype.shuffle) {Object.defineProperty(Array.prototype, 'shuffle', {enumerable: false,configurable: false,writable: false,value: function shuffle() {this.sort(function sort(a, b) {return (0.5 - Math.random());});}});}
Dieser Code mischt ein Array, indem eine Sortierfunktion überschrieben wird, die zufällig entscheidet, ob das verglichene Element größer oder kleiner ist.
Intern verwandelt die Rhino-Engine, in der die User Apps laufen, den Code in Java-Code um, so dass daraus ein Comparator wird. Wenn nun Elemente verglichen werden, dann kann es mit dieser Methode vorkommen, dass unlogische Verknüpfungen geschehen:
A kleiner B
B kleiner C
C kleiner A
Wenn ein Comparator so einen Fall entdeckt, dann wird die Meldung „Comparison method violates its general contract“ geworfen.
Wie sollte ein Array gemischt werden?
In der Klasse RandomOperations gibt es eine Methode, die genau das tut. Mit shuffleObjects erhält man ein gemischtes Array ganz ohne Fehlermeldung.