Search code examples
javacomparatorcompareto

java exception: Comparison method violates its general contract


I have already checked previous posts on this topic -- this and this. In spite of that, I couldn't figure out how the contract violation can happen in my code given below.

public class ScoreComparator 
implements Comparator<Map.Entry<?, Double>> {

public int compare(Map.Entry<?, Double> o1, 
        Map.Entry<?, Double> o2) {
    return o1.getValue().compareTo(o2.getValue());
}   
}

The way I make use of this is as follows:

List<Entry<String, Double>> entryList = 
        new ArrayList<Entry<String, Double>>(
                iterTypeScoreMap.get(keyToSort).entrySet());
Collections.sort(entryList, new ScoreComparator());

and iterTypeScoreMap is declared as follows

ConcurrentHashMap<String, Map<String, Double>> iterTypeScoreMap;

The map (iterTypeScoreMap) can change during the sort which is why I made a copy of the list and then call sort on it.

Since I am using the built-in compareTo method of Double, shouldn't that take care of the contracts? Another thing that makes this hard to debug is that this exception doesn't happen always; only happens during some of the runs. What could be the bug here?

Thanks in advance.


Solution

  • What's happening is that your sort order is changing during the sort operation, due to the entry values (scores) being changed concurrently.

    It doesn't help to make a copy of the map's entrySet() when the entries themselves are being concurrently modified. You'd have to deep copy the collection, in other words copy all of the Entry objects as well, in order to prevent the error. As it stands, the list you're sorting has references to the same Entry objects as the original map.