Reputation: 49
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?
Upvotes: 4
Views: 142
Reputation: 719199
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.
Upvotes: 7