Aus der Dokumentation von compare
.
The implementor must ensure sgn(x.compareTo(y)) == -sgn(y.compareTo(x))
for all x
and y
Subtraktionsbasierte Komparatoren erfüllen diese Bedingung nicht. Dies liegt daran, dass die Subtraktion überlaufen kann. Zum Beispiel
Integer.MIN_VALUE - 0
0 - Integer.MIN_VALUE
sind beide negativ.
Es gibt auch ein Problem mit der Art, wie Sie mit Date
s umgegangen sind. Aus der Dokumentation von compare
:
Finally, the implementor must ensure that x.compareTo(y)==0
implies that sgn(x.compareTo(z)) == sgn(y.compareTo(z))
, for all z
.
Ihre compare
Methode bricht dieses. wenn x
null
Zum Beispiel ist, ist y
1. Januar 1970 und z
ist der 2. Januar 1970 dann
compare(x, y) == 0 // x == null
compare(x, z) == 0 // x == null
compare(y, z) == -1 // January 1st is before January 2nd.
Ich kann das Verfahren wie folgt schreiben:
@Override
public int compare(Dto r1, Dto r2) {
int value = Integer.compare(r1.getOrder(), r2.getOrder());
if (value != 0)
return value;
Date date1 = r1.getDate();
Date date2 = r2.getDate();
if (date1 == null && date2 == null)
return 0;
if (date1 == null)
return -1;
if (date2 == null)
return 1;
return date1.compareTo(date2);
}
Ich habe es geschafft, das Problem zu reproduzieren , aber nur für List
s der Länge mindestens 32
. Unter diesem Link finden Sie eine Erklärung, warum eine List
der Größe mindestens 32
erforderlich ist. Why does this program using Collections.sort only fail for lists of size 32 or more?
public class Main {
private static final class NumAndDate {
private final int num;
private final Date date;
NumAndDate(int num, Date date) {
this.num = num;
this.date = date;
}
}
public static final class NumAndDateComparator implements Comparator<NumAndDate> {
@Override
public int compare(NumAndDate r1, NumAndDate r2) {
int value = 0;
value = r1.num - r2.num;
if (value == 0 && !isValueNull(r1.date, r2.date))
value = r1.date.compareTo(r2.date);
return value;
}
private boolean isValueNull(Date date, Date date2) {
return date == null || date2 == null;
}
}
public static void main(String[] args) {
NumAndDate[] array = {
new NumAndDate(0, new Date(0)),
new NumAndDate(0, new Date(1)),
new NumAndDate(0, null)
};
Random random = new Random();
for (int i = 0; i < 100; i++) {
for (int j = 0; j < 10000; j++) {
List<NumAndDate> list = new ArrayList<>();
int[] arr = new int[i];
for (int k = 0; k < i; k++) {
int rand = random.nextInt(3);
arr[k] = rand;
list.add(array[rand]);
}
try {
Collections.sort(list, new NumAndDateComparator());
} catch (Exception e) {
System.out.println(arr.length + " " + Arrays.toString(arr));
return;
}
}
}
}
}
Haben Sie sehr große Bestellungen (positiv oder negativ)? – immibis
Hallo immibis, Die Bestellungen reichen von 1-20 –
Die Frage, warum es bei Listen mit Länge> = 32 scheitert, wurde gerade [hier] beantwortet (http://stackoverflow.com/q/29866539/1639625) –