1

I am looking at some legacy code and I found a section that is causing me to get a “Comparison method violates its general contract!” error. I understand that this error is the result of the code not being transitive, but I don't fully understand how to fix it correctly.

Here is the code responsible for the error.

private void sortHistories(List<History> histories) {
        Collections.sort(histories, new Comparator<History>() {

            @Override
            public int compare(History o1, History o2) {

                return o1 == o2 ? 0
                        : o1 == null ? -1
                        : o2 == null ? 1
                        : o1.getFamilyMembers().equals(o2.getFamilyMembers()) ? 0 //getFamilyMembers() returns a string
                        : o1.getFamilyMembers() == null ? -1
                        : o2.getFamilyMembers() == null ? 1
                        : o2.getFamilyMembers().compareTo(o2.getFamilyMembers()) != 0 ?
                                o2.getFamilyMembers().compareTo(o2.getFamilyMembers())
                        : o1.getDisease().equals(o2.getDisease()) ? 0 //getDisease() also returns a string
                        : o1.getDisease() == null ? -1
                        : o2.getDisease() == null ? 1
                        : o1.getDisease().compareTo(o2.getDisease());
            }
        });
    }

Originally, the code was using == rather than equals() when comparing the strings getDisease() and getFamilyMembers(). I thought making the change from == to equals() would fix the problem, but that is not the case.

bob dylan
  • 647
  • 1
  • 10
  • 25

2 Answers2

2

The solution, thanks to HaifengZhang and YoungHobbit, is:

public int compare(History o1, History o2) {
                return o1 == o2 ? 0
                        : o1 == null ? -1
                        : o2 == null ? 1
                        : o1.getFamilyMembers() == null ? -1
                        : o2.getFamilyMembers() == null ? 1
                        : o1.getFamilyMembers() == o2.getFamilyMembers() ? 0
                        : o2.getFamilyMembers().compareTo(o1.getFamilyMembers()) != 0 ?
                                o2.getFamilyMembers().compareTo(o1.getFamilyMembers())
                        : o1.getDisease() == null ? -1
                        : o2.getDisease() == null ? 1
                        : o1.getDisease() == o2.getDisease() ? 0
                        : o1.getDisease().compareTo(o2.getDisease());
            }
bob dylan
  • 647
  • 1
  • 10
  • 25
0

Read the documentation carefully.Throwing this exception is a new Java7 feature.

More details here :: https://stackoverflow.com/a/8327575/3080158

The old behavior can be configured with a new system property: java.util.Arrays.useLegacyMergeSort.

http://www.oracle.com/technetwork/java/javase/compatibility-417013.html#source

enter image description here

http://docs.oracle.com/javase/7/docs/api/java/util/Comparator.html

enter image description here

Community
  • 1
  • 1
RBanerjee
  • 957
  • 1
  • 9
  • 18
  • Agree that this may get rid of the exception, but it won't fix the sort order, will it? – Erwin Bolwidt Dec 26 '16 at 05:39
  • Yes, to fix the sort order compactor should follow the contract,i.e for lt -1 , gt 1, and equals 0 , with transitivity. – RBanerjee Dec 26 '16 at 05:43
  • That's clear, so, how does the OP do that given the code that was posted? – Erwin Bolwidt Dec 26 '16 at 05:53
  • I didn't tried to solve the problem particularly, but if you go through the threads and docs ,the rule of thumb will be `check equality (a==b ? 0), then null(a or b is null -1,1),then compare or repeat for child` . If you check null first for example a==null? -1 then it might happen that b is also null , for which you should actually return 0. – RBanerjee Dec 27 '16 at 04:54