davidxxx davidxxx - 1 month ago 5
Java Question

Exception during Collections.sort()

A

java.lang.IllegalArgumentException: Comparison method violates its general contract!
is thrown when I do a
Collections.sort()
with a List of
ISimulationResultSet
.
I have not found the reason why contract is not respected.
If someone has a idea of the reason, it will be great to explain.

This is the Comparator I am using :

public int compare(ISimulationResultSet r1, ISimulationResultSet r2) {
final float r1Esperance = r1.getResults().getEsperanceGainOuPerte();
final float r2Esperance = r2.getResults().getEsperanceGainOuPerte();

final float r1PrctCibleAtteinte = r1.getResults().getPrctCibleAtteinte();
final float r2PrctCibleAtteinte = r2.getResults().getPrctCibleAtteinte();

if (r1Esperance / r2Esperance > 1.05F)
return -1;

else if (r1Esperance / r2Esperance < 0.95F) {
return 1;
}

else {

if (r1PrctCibleAtteinte == r2PrctCibleAtteinte) {
if (r1Esperance > r2Esperance)
return -1;

else if (r1Esperance < r2Esperance)
return 1;

return 0;
}

else if (r1PrctCibleAtteinte > r2PrctCibleAtteinte)
return -1;

else if (r1PrctCibleAtteinte < r2PrctCibleAtteinte)
return 1;

}
return 0;
}

Answer

The comparator has to be symetric, i.e. sgn(compare(x, y)) == -sgn(compare(y, x)) (sgn being the signum function here). This is not the case for your comparator:

Let a1 and a2 denote the values of x.getResults().getEsperanceGainOuPerte() and y.getResults().getEsperanceGainOuPerte() respectively and let b1 and b2 denote the values of x.getResults().getPrctCibleAtteinte() and y.getResults().getPrctCibleAtteinte() respectively.

Now consider the following:

1.05 < a1 < 1.052

a2 = 1

b2 > b1 

Therefore a2 / a1 > 0.95

compare(x, y) == -1;// first (r1Esperance / r2Esperance > 1.05F) is true

compare(y, x) == -1; // first 3 conditions false, (r1PrctCibleAtteinte > r2PrctCibleAtteinte) is true

That violates the contract.

Comments