Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Comparable Class - Comparison method violates its general contract

Tags:

java

I'm writing an isometric game that renders objects based on their Y coordinate, using a comparable class, sorting by their Y value, which changes. I am getting the error "Comparison method violates its general contract!" and have read about how to return a negative number, 0, or a positive number so I have implemented this:

public boolean equals(Entity e) {
    if ((e.y-y)==0)
        return (e.id == id);
    return (e.y == y);
}

public int compareTo(Entity e) {
    if ((e.y-y)==0)
        return (e.id - id);
    return (int) (e.y - y); // Render order by y coordinate
}

But I'm still getting the error. Is the sorting not going to work if the values change or am I doing something else wrong?

like image 425
Brian S Avatar asked Mar 13 '23 20:03

Brian S


1 Answers

The equals method is not involved in the contract, so we can ignore it.

I suspect that the problem is caused by integer overflow. The problem is that x - y does not always give you a positive answer if x > y and a negative number if x < y. If the difference between the numbers is large enough, then the express x - y will overflow and the result will have the wrong sign.

If that is the problem, then the simple solution is to use Integer.compare(x, y) instead of x - y

Another possibility is that the entities are being mutated at the same time as you are (for example) sorting them.


Float.compare(x, y) has worked much better.

I'd assumed that x and y were int. If they are float then the true cause of the problem is harder to understand. Either way, using Float.compare(x, y) is a better solution.

But if x and y are actually int, then using Float.compare(x, y) will give you incorrect answers for some x and y values. For close values of x and y with large enough magnitudes, the int to float conversion will lose precision, and Float.compare will say they are equal.

like image 182
Stephen C Avatar answered Apr 27 '23 16:04

Stephen C