-1

I am trying to sort arraylist based on comparing two strings using comparator ,but i end up with Comparison method violates its general contract error. How do i handle if null comparison occurs in the string.

Code

Collections.sort(keyList, new DIMsComparator<DIM>(sortField));


public static class DIMsComparator<T> implements Comparator<T> {
    String sortField = "";

    public DIMsComparator(String sortField) {
        this.sortField = sortField;
    }

    public int compare(T obj1, T obj2) {
        if (!(obj1 instanceof DIM) || !(obj2 instanceof DIM))
            return obj1 instanceof DIM ? -1 : obj2 instanceof DIM ? 1 : 0;
        DIM dim1 = (DIM) obj1;
        DIM dim2 = (DIM) obj2;
        // Changes for Grouping enhancement starts
        /*
         * if(dim1.getGroupName() != "" || dim2.getGroupName() != "") return -1;
         */
        // Changes for Grouping enhancement ends
        if (dim1.isTextLine())
            return 1;
        if (dim2.isTextLine())
            return -1;
        String[] mySortFields = Util.split(this.sortField, ",");
        for (int i = 0; i < mySortFields.length; i++) {
            if (mySortFields[i].equals(""))
                break;
            int value = compare(dim1, dim2, mySortFields[i]);
            if (value == 0)
                continue;
            else
                return value;
        }

        return dim1.dimSeqNo > dim2.dimSeqNo ? 1 : dim1.dimSeqNo < dim2.dimSeqNo ? -1 : 0;
    }

Error

[err] java.lang.IllegalArgumentException: Comparison method violates its general contract!
[err]   at java.util.TimSort.mergeLo(TimSort.java:788)
[err]   at java.util.TimSort.mergeAt(TimSort.java:525)
[err]   at java.util.TimSort.mergeCollapse(TimSort.java:452)
[err]   at java.util.TimSort.sort(TimSort.java:256)
[err]   at java.util.Arrays.sort(Arrays.java:1856)
[err]   at java.util.ArrayList.sort(ArrayList.java:1471)
[err]   at java.util.Collections.sort(Collections.java:186)
Smile
  • 3,832
  • 3
  • 25
  • 39

2 Answers2

4

As explained in https://stackoverflow.com/a/11441813/4090157 the exception message means, that your comparison does not follow the contract for every compare(..) method, which is:

  1. The implementor must ensure that sgn(compare(x, y)) == -sgn(compare(y, x)) for all x and y. (This implies that compare(x, y) must throw an exception if and only if compare(y, x) throws an exception.)
  2. The implementor must also ensure that the relation is transitive: ((compare(x, y)>0) && (compare(y, z)>0)) implies compare(x, z)>0.
  3. Finally, the implementor must ensure that compare(x, y)==0 implies that sgn(compare(x, z))==sgn(compare(y, z)) for all z.

One error in your code is, that you only consider the first dim if it is a textline:

if (dim1.isTextLine())
    return 1;
if (dim2.isTextLine())
    return -1;

So if both dim1 and dim2 are textlines both comparisons compare(dim1,dim2) and compare(dim2,dim1) will return 1, which violates the contract requirement 1.

And there may also be more inconsistancy in compare(dim1, dim2, mySortFields[i]) which is impossible to tell, since you did not add source code for this function.

ultimate
  • 653
  • 5
  • 18
1

Regarding [err] java.lang.IllegalArgumentException: Comparison method violates its general contract!

Your solution probably is not transitive

If A == B and B == C, then A must be equal to C.

Regarding your question:

How do i handle if null comparison occurs in the string.

Have a look at this answer

if(str != null && !str.isEmpty())

You should also take a look at this line int value = compare(dim1, dim2, mySortFields[i]); I'm not sure what it's supposed to do.

Hope this helps!

b3p0
  • 43
  • 5
  • Well the line I mentioned calls another `compare()` routine, obviously. The implied question is what does *that* do, and whether it complies with the specification. And why it wasn't posted in the question. – user207421 Feb 19 '20 at 11:21